我正在尝试将代码从IList
转换为IEnumerable
:
[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)]
属性。
我无法更改基类,因此看起来我被迫与IList
保持联系或手动实施IEnumerable
(并将属性添加到MoveNext()
)。
在这种情况下还有其他方法可以让收益率发挥作用吗?
答案 0 :(得分: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;
}
你失去了迭代器的延迟执行,但它会正常工作。
答案 1 :(得分: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);
}
}
答案 2 :(得分:1)
你可以分开你的方法吗?
[Something(123)]
public void GetAllFoosHelper()
{
SetupSomething();
}
public IEnumerable<Foo> GetAllFoos()
{
GetAllFoosHelper();
DataReader dr = RunSomething();
while (dr.Read())
{
yield return Factory.Create(dr);
}
}
答案 3 :(得分:1)
从您的描述中,听起来问题是SetupSomething仅查看堆栈跟踪上的直接调用方。如果它看起来更远(呼叫者的呼叫者),它会找到你的GetAllFocus调用和所需的属性。
我不记得我的头脑,但如果yield只是因为你的类还没有实现它而创建一个MoveNext()实现,也许你可以实现自己的MoveNext,把属性放在上面,和yield会找到并使用你的MoveNext()?只是一个疯狂的猜测。
答案 4 :(得分:1)
我可能遗漏了一些东西,但我无法理解在这里使用属性。你可能也写得像这样:
public IEnumerable<Foo> GetAllFoos()
{
SetupSomething(123);
// etc..
}
整个heckofalot也更快。更安全的是,当JIT编译器内联SetupSomething()时,你已经死了。