Атрибут потерян с доходностью - PullRequest
0 голосов
/ 07 апреля 2010

Есть некоторый код, который я пытаюсь преобразовать из 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 ]

3 голосов
/ 07 апреля 2010

Вы не можете использовать итераторы (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 голос
/ 07 апреля 2010

Я, наверное, что-то упускаю, но не вижу смысла использовать здесь атрибут. С таким же успехом вы могли бы написать это так:

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

Целый черт возьми, тоже быстрее. И безопаснее, вы мертвы в воде, когда JIT-компилятор вставляет SetupSomething ().

1 голос
/ 07 апреля 2010

Из вашего описания кажется, что проблема в том, что SetupSomething смотрит только на непосредственного абонента в трассировке стека. Если бы он посмотрел немного дальше (вызывающий абонент), он нашел бы ваш вызов GetAllFocus и требуемый атрибут.

Я не припоминаю, как на ладони, но если yield создает реализацию MoveNext () только потому, что ваш класс еще не реализует ее, возможно, вы можете реализовать свой собственный MoveNext, поместив в него атрибут и yield найдет и использует ваш MoveNext ()? Просто дикая догадка.

1 голос
/ 07 апреля 2010

Не могли бы вы разделить свой метод, как это?

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

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

  DataReader dr = RunSomething(); 
  while (dr.Read()) 
  { 
    yield return Factory.Create(dr); 
  } 
} 
1 голос
/ 07 апреля 2010

Вы можете заключить метод в другой метод, который выполняет всю необходимую предварительную обработку:

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

private IEnumerable<Foo> GetAllFoosInternal()
{
    DataReader dr = RunSomething();
    while (dr.Read())
    {
        yield return Factory.Create(dr);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...