Общая ковариантная ошибка в C#

Ниже мой код, я не знаю, почему 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 ответа

Решение

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# spec. Команда разработчиков отказалась от создания такой функции.

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

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

Func<Test, object> s = p => p.CreatedTime;
Другие вопросы по тегам