不同FW中的协方差导致代码中断

本文关键字:代码 中断 方差导 FW 不同 | 更新日期: 2023-09-27 18:24:56

我看过Jon Skeet在NDC 2010 上的演讲

他提到了一些有趣的事情:

public Class Base
{
 public void Foo(IEnumerable<string> strings){}
}
public Class Child:Base
{
 publc void Foo(IEnumerable<object> objects) {}
}
Main :
List<string> lst = new List<string>();
lst.Add("aaa");
Child c = new Child();
c.Foo(lst);

对于C#3,它将调用:Base.Foo

对于C#4,它将调用:Child.Foo

我知道这是因为协方差

问题:

这不是一个有点破坏代码的变化吗?有没有什么变通方法可以让这个代码继续像第3版一样工作?

不同FW中的协方差导致代码中断

是的,这是一个突破性的变化。任何时候,只要你将一个普遍无效的转换合法化,这都是一个突破性的改变。

不幸的是,很难在不进行任何破坏性更改的情况下为语言添加功能。如果您真的想查找事件,那么C#4中还有更多关于事件的内容。当然,这些不太可能影响到大多数开发人员。

在C#1和C#2之间也有类似的突破性变化,其中使用的实现在该代码的不同版本之间会发生变化:

using System;
public delegate void StringAction(string x);
public class Base
{
    public void Foo(string x)
    {
        Console.WriteLine("Base");
    }
}
public class Child : Base
{
    public void Foo(object x)
    {
        Console.WriteLine("Child");
    }
}
public class Test
{
    static void Main()
    {
        Child c = new Child();
        StringAction action = new StringAction(c.Foo);
        action("x");
    }
}

在这种情况下,编译器实际上会发出警告:

Test.cs(26,31): warning CS1707: Delegate 'StringAction' bound to
        'Child.Foo(object)' instead of 'Base.Foo(string)' because of new
        language rules

Jon当然是对的;这是一个突破性的变化。一个更容易看到这种突破性变化的方法是:

object x = new List<string>();
if (x is IEnumerable<object>) 
    Console.WriteLine(4);
else
    Console.WriteLine(3);

在打印3的C#中;在C#4中,它打印4。

当您更改类型系统时,您将更改过载解决的结果;事情就是这样。该功能的好处超过了可能中断的痛苦。

有变通办法吗?对不要把Child.Foo放在首位:

Base c = new Child();
c.Foo(list);