【问题标题】:Breaking change in .NET 4.0 with method overloading and covariance.NET 4.0 中的方法重载和协方差的重大变化
【发布时间】:2011-04-05 10:42:05
【问题描述】:

从 .NET 3.5 迁移到 4.0 后,我遇到了一个奇怪的问题,该函数导致 4.0 上的堆栈溢出,同时在 3.5 框架上完美运行。我用以下代码重现了这个问题:

public interface IPerson
{
    string Name { get; }
}

public class Person : IPerson
{
    public Person() { }

    public Person(IPerson source)
    {
        this.Name = source.Name;
    }

    public string Name { get; set; }
}

public class PersonList : List<Person>
{
    public void AddRange(IEnumerable<IPerson> source)
    {
        this.AddRange(source.Select(p => new Person(p)));
    }               
}

引发错误:

  IPerson otto = new Person { Name = "Otto" };
  IPerson fritz = new Person { Name = "Fritz" };

  PersonList list = new PersonList();

  IEnumerable<IPerson> persons = new[] { otto, fritz };
  list.AddRange(persons); //works on 3.5, stack overflow on 4.0

看看PersonListAddRange(IEnumerable&lt;IPerson&gt; source)方法。 在 3.5 中,方法 AddRange(IEnumerable&lt;Person&gt; source) 被调用,派生自 List&lt;Person&gt;。在 4.0 中,AddRange(IEnumerable&lt;IPerson&gt; source) 方法由于协方差而被调用(递归),尽管存在与输入参数完全匹配的参数 (IEnumerable&lt;Person&gt;I) 的更好匹配函数。

这种新行为是否有意并记录在案?

【问题讨论】:

    标签: c#-4.0 covariance overloading


    【解决方案1】:

    这是正确的 C# 行为,因为在 C# if any method on a more-derived class is an applicable candidate, it is automatically better than any method on a less-derived class, even if the less-derived method has a better signature match. 中,因此 C# 4 使 AddRange(IEnumerable&lt;IPerson&gt; source) 成为适用的候选者,然后更好的签名 AddRange(IEnumerable&lt;Person&gt; source) 在基类中,因此不会被选中。

    但由于规则,它在您的情况下很容易修复。

    public class PersonList  : List<Person>
    {
        public void AddRange(IEnumerable<IPerson> source)
        {
               base.AddRange(source.Select(p => new Person(p)));
        }    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 2011-04-06
      • 1970-01-01
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多