Ковариация в разных FW вызывает кодовый разрыв? - PullRequest
4 голосов
/ 18 февраля 2012

Я видел лекцию Джона Скита на 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?

Ответы [ 2 ]

7 голосов
/ 18 февраля 2012

Да, это серьезное изменение.Каждый раз, когда вы делаете недействительное преобразование легальным, это является серьезным изменением.

К сожалению, очень сложно добавлять функции в язык без внесения каких-либо критических изменений.В 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
5 голосов
/ 18 февраля 2012

Джон, конечно, прав;это серьезное изменение.Еще более простой способ увидеть это критическое изменение:

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

В C # 3, который печатает 3;в C # 4 он печатает 4.

Когда вы меняете систему типов, вы меняете результаты разрешения перегрузки;это просто так.Преимущество этой функции перевешивает боль возможных разрывов.

Есть ли обходной путь?Да.Во-первых, не звоните Child.Foo:

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