C#一般协变误差

C#一般协变误差,c#,generics,covariant,C#,Generics,Covariant,下面是我的代码, 我不知道为什么DateTime不能更改为Object, 有什么办法解决这个问题吗 public class Test { public DateTime CreatedTime { get; set; } } public class Test1 { } public class Test2 : Test1 { } static void Main(string[] args)

下面是我的代码, 我不知道为什么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 .... 
    }
公共类测试
{
公共日期时间CreatedTime{get;set;}
}
公共类Test1
{
}
公共类Test2:Test1
{
}
静态void Main(字符串[]参数)
{
Func fn1=null;
Func fn2=fn1;//成功
Func fn3=null;
Func fn4=fn3;//成功
Func expression1=p=>p.CreatedTime;
Func s=expression1;//无法将类型“System.Func”隐式转换为“System.Func”
Func s2=expression1;//无法隐式转换。。。。
}

您试图将委托类型
Func expression1
转换为委托类型
Func
,而不是将
DateTime
字段转换为
对象

如果这是您的初衷,请改用lambda表达式语法,如下所示:

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

您试图将委托类型
Func expression1
转换为委托类型
Func
,而不是将
DateTime
字段转换为
对象

如果这是您的初衷,请改用lambda表达式语法,如下所示:

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

DateTime
是一种值类型。将值类型转换为引用类型(本例中为对象
)是一种表示更改转换。它需要装箱值类型。对于引用类型,情况并非如此。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;
对象编译器生成函数(测试t){
return(object)匿名函数,返回sdatetime(t);
//在C#中,上述类型可以是隐式的,但我将其显式地用于演示
//必须表演的拳击。
}
Func convertedFunction=compilerGeneratedFunction;

但是产生的委托会指向一个完全不同的函数,这会导致一些不好的事情,比如不遵守C#spec中的委托平等规则。设计团队决定不生成这样的函数

日期时间是一种值类型。将值类型转换为引用类型(本例中为对象
)是一种表示更改转换。它需要装箱值类型。对于引用类型,情况并非如此。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;
对象编译器生成函数(测试t){
return(object)匿名函数,返回sdatetime(t);
//在C#中,上述类型可以是隐式的,但我将其显式地用于演示
//必须表演的拳击。
}
Func convertedFunction=compilerGeneratedFunction;

但是产生的委托会指向一个完全不同的函数,这会导致一些不好的事情,比如不遵守C#spec中的委托平等规则。设计团队决定不生成这样的函数

但是我想了解通用协变函数。Func可以改为Func,因为Test2派生了Test1,我认为所有类型都派生了System.Object,为什么我不能将Func改为Func你的问题措辞不清楚,所以我显然回答了错误的隐式问题。Mehrdad有你正确的答案。在这种情况下,DateTime作为值类型无法转换为引用类型。但我想了解泛型协变。Func可以更改为Func,因为Test2派生了Test1,我认为所有类型都派生了System.Object,为什么我不能把Func改成Func你的问题措辞含糊不清,所以我显然回答了错误的隐含问题。Mehrdad有你正确的答案。在这种情况下,DateTime作为值类型无法转换为引用类型。“所有指针都具有相同的大小”,我无法获得此信息。你能解释一下吗?@saurabh:暂时把指针忘得一干二净;这是一个实现细节。想一想:在IL级别,将值类型转换为引用类型需要一个
指令,而将引用类型转换为其基类则是禁止操作的。对于引用类型,在运行时不需要进行任何转换。您可以在C#中的继承层次结构中强制转换引用类型,以使编译器满意;您不能为强制转换生成代码。“所有指针都有相同的大小”,我无法得到这个。你能解释一下吗?@saurabh:暂时把指针忘得一干二净;这是一个实现细节。想一想:在IL级别,将值类型转换为引用类型需要一个
指令,而将引用类型转换为其基类则是禁止操作的。对于引用类型,在运行时不需要进行任何转换。您可以在C#中的继承层次结构中强制转换引用类型,以使编译器满意;你不能为演员组生成代码。