一般方法不支持强制转换为基类型

时间:2015-12-17 14:57:04

标签: 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<T> : IGenericOrder<T> where T : new()
    {
        public Func<T, int> GetStatement(string name)
        {
            return (T) => 4;
        }    
    }
}

现在,当我创建该类的实例并将其强制转换回IGenericOrder<object>

var sorter = (IGenericOrder<object>) new GenericOrder<Foo>();

我得到例外:

  

InvalidCastException:类型GenericOrder<Foo>的实例无法强制转换为IGenericOrder<object>

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

  

无效方差:类型参数&#39; T&#39;必须在IGenericOrder<T>.GetStatement(string)上违反有效。 &#39; T&#39;是协变的。

当我从here读取时,协方差只能在

时使用
  

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

这是否意味着我不能对他们自己返回通用实例的方法使用共同/逆变?

我正在使用.Net 4.5

2 个答案:

答案 0 :(得分:2)

要了解正在进行的操作,请查看Func<T,TResult>委托的定义:

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

如您所见,其第一个类型参数Tin参数。因此,您不能将out参数用作Func的第一个类型参数。第二个类型参数TResultout,因此使用T作为TResult可行:

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);
    }    
}

Demo.

答案 1 :(得分:1)

您使用T作为Func的第一个类型参数,因此唯一有效的模式是 contravariance ,因为T表示函数的类型参数。你试图用你的演员实现的是不安全的:你说的是“这是一个以Foo为参数的函数。请将此视为一个以object为参数的函数。”如果你有一个Func<int, T>,你可以使用协方差,因为返回Foo的函数也可以被视为一个返回object的函数。