两种通用类型之间的转换失败
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>>
)。
我正在尝试使用 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>>
)。