【问题标题】:Iterator blocks and inheritance迭代器块和继承
【发布时间】:2011-01-26 19:56:35
【问题描述】:

给定一个具有以下接口的基类:

public class Base
{
    public virtual IEnumerable<string> GetListOfStuff()
    {
        yield return "First";
        yield return "Second";
        yield return "Third";
    }
}

我想创建一个覆盖该方法的派生类,并添加自己的东西,如下所示:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        foreach (string s in base.GetListOfStuff())
        {
            yield return s;
        }

        yield return "Fourth";
        yield return "Fifth";
    }
}

但是,我收到一条警告,“无法验证通过迭代器中的基本关键字访问成员”。

那么这个问题的公认解决方案是什么?

【问题讨论】:

  • 请注意,这在 C# 4 中已修复(并且......在 C# 3 SP 1 中?也许?我不记得我们是否得到了这个修复。我们打算这样做。)编译器现在为您生成帮助器。
  • 我在 VS2008 SP1 中收到警告。

标签: c# inheritance iterator


【解决方案1】:

怎么样:

public class Derived : Base
{
    public override IEnumerable<string> GetListOfStuff()
    {
        return base.GetListOfStuff().Concat(GetMoreStuff());        
    }
    private IEnumerable<string> GetMoreStuff()
    {
        yield return "Fourth";
        yield return "Fifth";
    }
}

【讨论】:

  • 这个类中的东西不是辅助函数,而是辅助函数。好主意!
【解决方案2】:

顺便说一下,这种奇怪行为的原因是 CLR 安全团队在 v2 发布之前更改了验证程序,因此无法验证从另一个类的方法对一个类的虚拟方法进行非虚拟调用类。

有关此问题的进一步解释,请参阅我几年前关于该主题的文章。

http://blogs.msdn.com/ericlippert/archive/2005/11/14/why-are-base-class-calls-from-anonymous-delegates-nonverifiable.aspx

现在已经过时了;我们已经修复了编译器,现在它会为您生成帮助器。

【讨论】:

    【解决方案3】:

    似乎一种解决方案是简单地遵循"manual" 所说的:创建一个辅助函数。

    所以现在我已经这样解决了:

    public class Derived : Base
    {
        private IEnumerable<string> GetBaseStuff()
        {
            return base.GetListOfStuff();
        }
    
        public override IEnumerable<string> GetListOfStuff()
        {
            foreach (string s in GetBaseStuff())
            {
                yield return s;
            }
    
            yield return "Fourth";
            yield return "Fifth";
        }
    }
    

    但我也对其他解决方案感到好奇,如果它们存在的话。

    【讨论】:

      【解决方案4】:

      这是因为迭代器变成了一个私有类,并且从内部类访问超类方法是不可验证的(因为它必须强制“this”指针指向自身以外的东西)。

      尝试在Derived 中创建一个新的私有方法:

      private IEnumerable<string> GetBaseListOfStuff()
      {        
          return base.GetListOfStuff();
      }
      

      并调用它而不是base.GetListOfStuff()

      【讨论】:

        【解决方案5】:

        以防万一有人仍在寻找答案。有同样的问题,并且能够通过这样做来使其工作:

        public class Derived : Base
        {
            public override IEnumerable<string> GetListOfStuff()
            {
                var enumerator = base.GetListOfStuff().GetEnumerator();
        
                while(enumerator.MoveNext())
                {
                     yield return enumerator.Current;
                }
        
                yield return "Fourth";
                yield return "Fifth";
        
                yield break;
            }
        }
        

        【讨论】:

        • 这基本上是我的答案,只是直接使用枚举器而不是foreach
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-18
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多