Breaking change in .NET 4.0 with method overloading and covariance
after migrating from .NET 3.5 to 4.0 i have a strange problem with a function resulting in stack overflow on 4.0 while working perfectly on the 3.5 framework. I reproduced the problem with the following code:
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)));
    }               
}
Provoking the error:
  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
Have a look at the AddRange(IEnumerable<IPerson> source) method of PersonList.
In 3.5, the method AddRange(IEnumerable<Person> source) is called, derived from List<Person>. In 4.0 the AddRange(IEnumerable<IPerson> source) method is called (recursion) due to covariance, in spite the fact that a better matching function with a parameter (IEnumerable<Person>I) exactly matching the input parameter exists.
Is that new behaviour intended and documented?开发者_如何学JAVA
This is proper C# behavior because in 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. So C# 4 has made AddRange(IEnumerable<IPerson> source) an applicable candidate and then the better signature AddRange(IEnumerable<Person> source) is in the base class so it doesn't get picked.
But it's easily fixable in your case, because of the rule.
public class PersonList  : List<Person>
{
    public void AddRange(IEnumerable<IPerson> source)
    {
           base.AddRange(source.Select(p => new Person(p)));
    }    
}
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论