两种通用类型之间的转换失败

Conversion fails between two Generic Types

我正在尝试使用 T 类型的 linq 表达式创建对象类型 (MyObject)。我的 class 声明 T 的值必须是 BaseModel 类型(这是我创建的对象) .以下是 MyObject 的构造方式:

public class MyObject<T> where T : BaseModel
{
    public Type MyType;

    public Expression<Func<T, bool>> MyExpression;
}

我所有的模型都继承自 BaseModel。示例:

public class MyModel : BaseModel
{
    public string Name { get; set; }
}

我的对象在通用静态中使用 class:

public static class MyStaticClass
{
    private static Dictionary<MyObject<BaseModel>, string> MyDictionary = new Dictionary<MyObject<BaseModel>, string>();

    public static AddMyObjectsToDictionary(List<MyObject<BaseModel>> myObjects)
    {
        //CODE
    }

    //REST OF CODE
}

然后当我的应用程序加载时它会执行以下操作(此处抛出错误):

List<MyObject<BaseModel>> myObjects = new List<MyObject<BaseModel>>();

myObjects.Add(new MyObject<MyModel>()
{
    MyType = typeof(MyModel),
    MyExpression = p => p.Name == "myname"
});

MyStaticClass.AddMyObjectsToDictionary(myObjects);

与命名空间一起抛出的确切错误消息,以显示每个对象所在的项目:

cannot convert from 'ProjectANamespace.MyObject<ProjectBNamespace.MyModel>' to 'ProjectANamespace.MyObject<ProjectANamespace.BaseModel>'

我需要能够在 MyModel 中创建一个通用表达式,但是我无法在 MyStaticClass 中指定 MyModel,因为它是一个通用 class,它与 BaseModel 一起位于另一个项目中。

有人知道如何解决这个问题吗?

为此,我相信您需要使用 Covariance features of c# 4+. In particular, I believe you need to use the out 修饰符。经过一些测试,我发现这对 类 不起作用。但是,如果您在模式中引入一个接口,您就可以完成这项工作。比如下面编译

public class Base
{

}

public class Derived : Base
{

}

public interface IWrapper<out T> where T : Base
{

}

public class Wrapper<T> : IWrapper<T> where T : Base
{

}

public static class Methods
{
  public static void Test()
  {
    var obj = new List<IWrapper<Base>>();
    obj.Add(new Wrapper<Derived>());
  }
}

MyObject<MyModel> 不是 MyObject<BaseModel>,就像 List<string> 不是 List<object> 一样。它在泛型之外的工作方式也相同——通用概念称为 variance,并描述类型的有效替换。由于 MyObject 对于 T 既不是协变也不是逆变,因此对于任何不相同的 T 和 U,MyObject<T> 永远不可能是 MyObject<U> .

接口和委托中的泛型类型参数可以是协变和逆变的,但不能同时。例如,您的 Func<T, bool> 是逆变的,因为您可以替换从 T 派生的类型而不是 T 本身。所以 Func<BaseModel, bool> 可以转换为 Func<MyModel, bool>(就像 MyModel 可以作为 BaseModel 的参数 "instead" 传递一样),但反之则不行。类似地,Func<T, U> 相对于 T 是逆变的,相对于 U 是协变的——你不能从一个函数中 return object return 类型 string.

因此,即使您将定义更改为使用接口来添加方差,您也只能获得逆方差,而不是您想要的协方差。太糟糕了 - 没有安全的方法可以做到这一点。

相反,如果您需要非通用接口,只需添加一个非通用接口即可。而已。您将拥有 List<IMyObject>,而不是 List<MyObject<BaseModel>>,您可以根据需要使用它(可能通过转换,或者只是公开简单的 Expression 而不是 Expression<Func<T, bool>>)。