.NET 4.0 中方法重载和协变的重大变化

发布于 2024-10-31 02:26:17 字数 1185 浏览 2 评论 0原文

从 .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(IEnumerablesource) 方法。 在 3.5 中,调用从 List 派生的方法 AddRange(IEnumerablesource)。在 4.0 中,尽管事实上带有参数的更好匹配函数 (IEnumerableI< /code>) 存在与输入参数完全匹配的情况。

这种新行为是有意为之并记录在案的吗?

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?

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

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

发布评论

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

评论(1

半窗疏影 2024-11-07 02:26:22

这是正确的 C# 行为,因为在 C# 中,如果更多派生类上的任何方法都是适用的候选者,它自动优于派生较少的类上的任何方法,即使派生较少的方法具有更好的签名匹配。 因此,C# 4 制作了 AddRange(IEnumerablesource) 一个适用的候选者,然后更好的签名 AddRange(IEnumerablesource) 位于基类中,因此不会被选中。

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

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

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