在开发一个应该处理各种泛型lambda表达式的类时,我遇到了一个相当熟悉的漏洞:我有一个MyClass<T>
类,我试图将MyClass<string>
强制转换为MyClass<object>
,像这样:
MyClass<string> myClassString = GetMyClass(); // Returns MyClass<String>
MyClass<object> myClassObject = myClassString;
这样做会返回一个编译错误,说明两种类型之间没有隐式转换,但确实存在显式转换。所以我添加了显式转换:
MyClass<object> myClassObject = (MyClass<object>)myClassString;
现在代码已编译,但在运行时失败,声称转换是非法的。
我使用的是Visual Studio 2012,代码是使用C#5编译的可移植类库项目的一部分。
为了确保,我替换了MyClass
IList
- 出现了相同的行为 - 允许显式转换,但在运行时失败。
为什么呢?为什么编译器会接受这个?如果它在运行时失败,那么显式转换的重点是什么?
答案 0 :(得分:5)
为了允许演员表,您需要将其标记为协变。但是,协方差仅允许用于接口(和委托)。这看起来像是:
interface MyInterface<out T> ...
您可以编译显式强制转换的原因可能是编译器假定GetMyClass()
的返回值可能是MyClass<object>
。但没有宣言就很难说。
答案 1 :(得分:3)
为了能够将MyClass<string>
投射到MyClass<object>
,您需要完成以下任务:
MyClass<T>
必须是一个界面,例如IMyClass<T>
。out
关键字添加到类型参数T
,使类型参数协变。T
可能只出现在界面成员的输出位置。例如:
public interface IMyClass<out T>
{
T GetItem(); // T in an output position
}
现在你可以施展它了:
IMyClass<string> myClassString;
IMyClass<object> myClassObject = (IMyClass<object>)myClassString;
答案 2 :(得分:0)
如果您有A类和B类,并且想要将B转换为A,则必须满足以下条件之一:
在您的情况下,上述情况均属实,因此演员表无效。
如果您的类实现IEnumerable,您可以使用扩展方法
using System.Linq
...
MyClass<Object> asObject = GetMyClass().Cast<Object>();
否则,编写一个执行转换的显式运算符或函数:
public MyClass<Base> ConvertToBase<Base, Derived>(MyClass<Derived>) where Derived : Base
{
// construct and return the appropriate object
}
答案 3 :(得分:-2)