属性因收益而丢失

时间:2010-04-07 17:29:07

标签: c# reflection attributes yield

我正在尝试将代码从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())。

在这种情况下还有其他方法可以让收益率发挥作用吗?

5 个答案:

答案 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()时,你已经死了。