C# 泛型方法不支持转换为基类型

C# 泛型方法不支持转换为基类型,c#,generics,covariance,C#,Generics,Covariance,我有一个接口IGenericOrder,如下所示: using System; using System.Linq.Expressions; namespace MyNamespace { interface IGenericOrder<T> where T : new() { Func<T, int> GetStatement(string name); } public class GenericOrder<

我有一个接口
IGenericOrder
,如下所示:

using System;
using System.Linq.Expressions;

namespace MyNamespace
{
    interface IGenericOrder<T> where T : new()
    {
        Func<T, int> GetStatement(string name);
    }


    public class GenericOrder<T> : IGenericOrder<T> where T : new()
    {
        public Func<T, int> GetStatement(string name)
        {
            return (T) => 4;
        }    
    }
}
使用系统;
使用System.Linq.Expressions;
名称空间MyNamespace
{
接口IGenericOrder,其中T:new()
{
Func GetStatement(字符串名称);
}
公共类GenericOrder:IGenericOrder,其中T:new()
{
public Func GetStatement(字符串名称)
{
返回值(T)=>4;
}    
}
}
现在,当我创建该类的实例并将其转换回
IGenericOrder

var-sorter=(IGenericOrder)新的GenericOrder();
我得到一个例外:

InvalidCastException:type
GenericOrder
的实例无法强制转换为
IGenericOrder

这似乎很清楚,因为接口
IGenericOrder
不是协变的。但是,如果我使接口协变(
接口IGenericOrder
),我会得到一个编译器错误:

无效差异:类型参数“T”必须在
IGenericOrder.GetStatement(string)
上反向有效T’是协变的

正如我从协方差中读到的,只有在

[泛型类型参数]仅用作方法返回类型,不用作形式方法参数的类型

这是否意味着我不能对自身返回泛型实例的方法使用协方差/逆变


我使用.Net 4.5

您使用
T
作为
Func
的第一个类型参数,因此唯一有效的模式是逆变模式,因为
T
表示函数参数的类型。您试图通过强制转换实现的是不安全的:您说的是“这是一个函数,它将
Foo
作为参数。请将此函数视为一个函数,它将任何
对象
作为参数。”如果您使用的是
Func
,则可以使用协方差,因为返回
Foo
的函数也可以看作是返回
对象的函数

要了解发生了什么,请查看委托的定义:

public delegate TResult Func<in T, out TResult>(
    T arg
)

是的。我的意思是,你已经掌握了你需要的所有信息,并且你正确地解释了它。这甚至是有道理的。你还想找什么?嗯,这就是错误告诉我的,但我不完全理解这件事的激烈程度。从您的角度来看,什么才是有意义的呢?试想一下——您返回的函数的参数类型为
T
。如果允许您将接口强制转换为
IGenericOrder
,它将返回一个函数,该函数采用
object
类型的参数。并非所有的
T
s都是
object
s-您破坏了类型安全。另一方面,您可以使用
T
contra variant-将子类而不是父类作为参数传递是有效的。。。以某种方式谢谢,我明白了,有了
Func
的签名,这一点就显而易见了。谢谢你指出这一点
public delegate TResult Func<in T, out TResult>(
    T arg
)
interface IGenericOrder<out T> where T : new() {
    Func<int,T> GetStatement(string name);
}

public class GenericOrder<T> : IGenericOrder<T> where T : new() {
    public Func<int,T> GetStatement(string name) {
        return (x) => default(T);
    }    
}