铸造MyClass<;字符串>;到MyClass<;对象>;在运行时失败
本文关键字:gt lt MyClass 运行时 失败 字符串 铸造 对象 | 更新日期: 2023-09-27 18:21:27
在开发一个应该处理各种泛型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
——出现了相同的行为——允许显式转换,但在运行时失败。
为什么?编译器为什么接受这个?如果显式转换在运行时失败,它有什么意义?
为了允许强制转换,您需要将其标记为协变。但是,协方差只允许用于接口(和委托)。这看起来像:
interface MyInterface<out T> ...
可以编译显式强制转换的原因可能是编译器假设GetMyClass()
的返回值可以是MyClass<object>
。但如果没有宣言,这很难说。
要将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;
如果您有类A和B,并且您想将B强制转换为A,那么以下其中一个必须为真:
- B派生/实现A,反之亦然
- 有一个从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
}
使用Conversion运算符实现将类强制转换为其他类
http://msdn.microsoft.com/en-us/library/85w54y0a.aspx
http://msdn.microsoft.com/en-us/library/09479473(v=vs.80).aspx