Общая ковариантная ошибка C # - PullRequest
1 голос
/ 12 октября 2010

Ниже приведен мой код, я не знаю, почему DateTime не может измениться на Object, есть идеи для решения этой проблемы?

    public class Test
    {
        public DateTime CreatedTime { get; set; }
    }
    public class Test1
    {

    }
    public class Test2 : Test1
    {
    }
    static void Main(string[] args)
    {

        Func<Test, ArgumentException> fn1 = null;
        Func<Test, Exception> fn2 = fn1;// success 

        Func<Test, Test2> fn3 = null;
        Func<Test, Test1> fn4 = fn3;//success  

        Func<Test, DateTime> expression1 = p => p.CreatedTime;
        Func<Test, object> s = expression1; // Cannot implicitly convert type 'System.Func<IlReader.Program.Test,System.DateTime>' to 'System.Func<IlReader.Program.Test,object>'    
        Func<Test, ValueType> s2 = expression1; // cannot implicatily convert .... 
    }

Ответы [ 2 ]

6 голосов
/ 12 октября 2010

DateTime является типом значения.Преобразование типа значения в ссылочный тип (в данном случае object) является преобразованием с изменением представления.Требуется бокс типа значения.Для ссылочных типов это не так.CLR реализует ссылку с указателями, и все указатели имеют одинаковый размер.Ссылка на производный класс просто интерпретируется как ссылка на базовый класс.По этой причине вы не можете использовать ковариацию подобным образом для типов значений.

Теоретически, компилятор мог бы сгенерировать промежуточную функцию, такую ​​как:

object compilerGeneratedFunction(Test t) {
    return (object)anonymousFunctionThatReturnsDateTime(t);
    // The above cast can be implicit in C# but I made it explicit to demonstrate
    // boxing that has to be performed.
}

Func<Test, DateTime> convertedFunction = compilerGeneratedFunction;

Но полученный делегатбудет указывать на совершенно другую функцию, вызывающую плохие вещи, такие как несоблюдение правил равенства делегатов в спецификации C #.Команда разработчиков отказалась от создания такой функции.

0 голосов
/ 12 октября 2010

Вы пытаетесь преобразовать тип делегата Func<Test, DateTime> expression1 в тип делегата Func<Test, object>, а не поле DateTime в object.

Если это было ваше первоначальное намерение, используйте лямбдуВместо этого синтаксис выражения, например, так:

Func<Test, object> s = p => p.CreatedTime;
...