ковариация делегатов и контравариантность - PullRequest
7 голосов
/ 22 июля 2011

Рассмотрим следующий фрагмент кода

namespace ConsoleApplication1
{

public delegate TResult Function<in T, out TResult>(T args);

 class Program
 {
      static void Main(string[] args)
    {
        Program pg =new Program();
        Function<Object, DerivedClass> fn1 = null;
        Function<String, BaseClass> fn2 = null;
        fn1 = new Function<object, DerivedClass>(pg.myCheckFuntion)
        fn2=fn1;
        fn2("");// calls myCheckFuntion(Object a)
        pg.myCheckFuntion("Hello"); //calls myCheckFuntion(String a)
     }

     public DerivedClass myCheckFuntion(Object a)
    {
        return  new DerivedClass();
    }
    public DerivedClass myCheckFuntion(String a)
    { 
        return new DerivedClass();
    }
 }

, почему вызов делегата и обычный вызов метода вызывают разные методы.

Ответы [ 3 ]

8 голосов
/ 22 июля 2011

Делегат связан с myCheckFuntion(Object) во время компиляции - вы говорите ему найти метод, который принимает Object.Это связывание только с одним методом - оно не выполняет разрешение перегрузки во время выполнения на основе фактического типа аргумента.

Когда вы вызываете pg.myCheckFuntion("Hello") , будет привязываться к myCheckFuntion(String) во время компиляции, потому что "Hello" является строкой, и преобразование из строки в строку предпочтительнее преобразования из строки в объект в разрешении перегрузки.

Обратите внимание, что если вы напишите:

object text = "Hello";
pg.myCheckFuntion(text);

тогда , что назовет myCheckFuntion(Object).

2 голосов
/ 22 июля 2011

fn2 вызывает myCheckFuntion(Object a) из-за его объявления:

fn1 = new Function<object, DerivedClass>(pg.myCheckFuntion)
fn2 = fn1; // here you copy the reference

pg.myCheckFuntion("Hello"); вызывает myCheckFuntion(Object a), потому что String является более ограничительным типом, чем object.

если вы приведете строку к Object:

pg.myCheckFuntion((object)"Hello");

, она вызовет другой метод.

1 голос
/ 22 июля 2011

Сам объект делегата все еще указывает только на одну функцию, а не на диапазон функций. Дисперсия co (ntra) позволяет вам указывать только на большую область типов функций. Таким же образом вы можете присвоить все виды значений переменной типа object, но меньше переменной типа string. Несмотря на это, переменная будет по-прежнему иметь только один фактический тип и одно фактическое значение в любой момент времени.

...