0

我正在尝试将一些代码转换IListIEnumerable

[Something(123)]
public IEnumerable<Foo> GetAllFoos()
{
  SetupSomething();

  DataReader dr = RunSomething();
  while (dr.Read())
  {
    yield return Factory.Create(dr);
  }
}

问题是,SetupSomething()来自基类并使用:

Attribute.GetCustomAttribute(
    new StackTrace().GetFrame(1).GetMethod(), typeof(Something))

yield最终创建MoveNext()MoveNext()调用SetupSomething(),并且MoveNext()没有[Something(123)]属性。

我无法更改基类,因此看来我被迫保留IListIEnumerable手动实现(并将属性添加到MoveNext())。

在这种情况下,有没有其他方法可以使产量起作用?

4

5 回答 5

3

如果您需要堆栈框架功能,则不能使用迭代器(yield)。正如您所发现的,这会将您的方法重写为实现IEnumerable<T>.

但是,您可以轻松地将其修改为:

[Something(123)]
public IEnumerable<Foo> GetAllFoos()
{
  SetupSomething();

  List<Foo> results = new List<Foo>();
  DataReader dr = RunSomething();
  while (dr.Read())
  {
    results.Add(Factory.Create(dr));
  }
  return results;
}

您失去了迭代器的延迟执行,但它会正常工作。

于 2010-04-07T17:32:18.670 回答
1

您可以将该方法包装在另一个方法中,该方法执行所有必需的预处理:

[Something(123)]
public IEnumerable<Foo> GetAllFoos()
{
    SetupSomething();
    return GetAllFoosInternal();
}

private IEnumerable<Foo> GetAllFoosInternal()
{
    DataReader dr = RunSomething();
    while (dr.Read())
    {
        yield return Factory.Create(dr);
    }
}
于 2010-04-07T17:32:37.660 回答
1

你能像这样把你的方法分开吗?

[Something(123)]
public void GetAllFoosHelper()
{
  SetupSomething(); 
}

public IEnumerable<Foo> GetAllFoos() 
{ 
  GetAllFoosHelper();

  DataReader dr = RunSomething(); 
  while (dr.Read()) 
  { 
    yield return Factory.Create(dr); 
  } 
} 
于 2010-04-07T17:33:41.940 回答
1

根据您的描述,听起来问题在于 SetupSomething 仅查看堆栈跟踪上的直接调用者。如果它看起来更远一点(调用者的调用者),它会找到您的 GetAllFocus 调用和所需的属性。

我不记得了,但是如果 yield 只是因为您的类还没有实现它而创建 MoveNext() 实现,也许您可​​以实现自己的 MoveNext,将属性放在上面,然后 yield 将查找并使用您的 MoveNext()?只是一个疯狂的猜测。

于 2010-04-07T17:35:30.463 回答
1

我可能遗漏了一些东西,但我无法理解在这里使用属性。你不妨这样写:

public IEnumerable<Foo> GetAllFoos()
{
  SetupSomething(123);
  // etc..
}

整个 heckofalot 也更快。更安全的是,当 JIT 编译器内联 SetupSomething() 时,你就死定了。

于 2010-04-07T18:11:08.910 回答