属性随着产量而丢失

发布于 2024-08-27 15:52:06 字数 786 浏览 16 评论 0原文

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

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

There is some code that I'm trying to convert from IList to IEnumerable:

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

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

The problem is, SetupSomething() comes from the base class and uses:

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

yield ends up creating MoveNext(), MoveNext() calls SetupSomething(), and MoveNext() does not have the [Something(123)] attribute.

I can't change the base class, so it appears I am forced to stay with IList or implement IEnumerable manually (and add the attribute to MoveNext()).

Is there any other way to make yield work in this scenario?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

咋地 2024-09-03 15:52:06

如果您需要堆栈帧功能,则不能使用迭代器(yield)。正如您所发现的,这会将您的方法重写为实现 IEnumerable 的自定义类。

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

[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;
}

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

You can't use iterators (yield) if you require the stack frame functionality. As you've discovered, this rewrites your method into a custom class that implements IEnumerable<T>.

However, you can easily just rework this to:

[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;
}

You lose the deferred execution of the iterator, but it will work properly.

日暮斜阳 2024-09-03 15:52:06

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

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

private IEnumerable<Foo> GetAllFoosInternal()
{
    DataReader dr = RunSomething();
    while (dr.Read())
    {
        yield return Factory.Create(dr);
    }
}

You can wrap the method in another method that does all required preprocessing:

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

private IEnumerable<Foo> GetAllFoosInternal()
{
    DataReader dr = RunSomething();
    while (dr.Read())
    {
        yield return Factory.Create(dr);
    }
}
小伙你站住 2024-09-03 15:52:06

你能像这样分解你的方法吗?

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

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

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

Could you split your method up, like this?

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

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

  DataReader dr = RunSomething(); 
  while (dr.Read()) 
  { 
    yield return Factory.Create(dr); 
  } 
} 
染柒℉ 2024-09-03 15:52:06

从您的描述来看,问题似乎在于 SetupSomething 仅查看堆栈跟踪上的直接调用者。如果它进一步向上查找(调用者的调用者),它将找到您的 GetAllFocus 调用和所需的属性。

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

From your description, it sounds like the problem is that SetupSomething is only looking at the immediate caller on the stack trace. If it looked a little further up (caller's caller) it would find your GetAllFocus call and the desired attribute.

I don't recall off the top of my head, but if yield is creating a MoveNext() implementation only because your class doesn't already implement it, perhaps you can implement your own MoveNext, put the attribute on it, and yield will find and use your MoveNext()? Just a wild guess.

泅人 2024-09-03 15:52:06

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

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

也快了一大截。更安全的是,当 JIT 编译器内联 SetupSomething() 时,您就完蛋了。

I'm probably missing something, but I can't make sense of using an attribute here. You might as well have written it like this:

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

A whole heckofalot faster too. And safer, you're dead in the water when the JIT compiler inlines SetupSomething().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文