无效的强制转换异常泛型
本文关键字:异常 泛型 转换 无效 | 更新日期: 2023-09-27 18:29:23
我遇到了这个问题,我正在使用反射从类中提取属性,但问题是反射将它们作为对象返回,我无法将其放入我的实际类型中。
举个例子,如果这是类:
public class Row<T>
{
public static explicit operator Row<object>(Row<T> o)
{
return new Row<object>
{
Name = o.Name,
Value = o.Value
};
}
public string Name { get; set; }
public T Value { get; set; }
}
从一说Row<bool>
到Row<object>
作品的选角:
var a = new Row<bool>
{
Name = "Foo",
Value = true
};
var b = (Row<object>)a; // Works
但是当我尝试从object
转到Row<object>
时,它似乎忽略了我的显式运算符并抛出了一个System.InvalidCastException:
var c = (object) a; // Simulate getting from reflection
var d = (Row<object>) c; // System.InvalidCastException
我错过了什么?
使用 dynamic
而不是 object
强制运行时实际类型检查:
var c = (dynamic)a;
var d = (Row<object>)c; // Works fine
它将调用您的Row<T> -> Row<object>
铸造操作员。
这里的问题是,除非在尝试强制转换的值的静态类型上定义了转换运算符,否则转换不会查找转换运算符。在您的示例中,c
的静态类型是object
的,并且object
既不派生自转换运算符,也不具有要Row<object>
的转换运算符,从而导致运行时异常。
看起来这个问题可以很容易地通过更好的设计来回避。
您希望将任何类型的Row<T>
视为Row<object>
,而转换运算符所做的只是解决这些类型不分层相关的事实。那么,为什么不使它们相关并首先避免问题呢?
例如:
public abstract class Row
{
public string Name { get; set; }
public object Value { get; protected set; }
}
public class Row<T> : Row
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
这似乎可以满足您的需求:
- 转换问题已解决,因为您现在可以将任何类型的
Row<T>
转换为基类Row
(在初始设计中接管Row<object>
的责任(,并且无论Value
是什么类型,都可以轻松访问Name
和Value
。 Row.Value
二传手受到保护,因此您不能将Row<int>
投向Row
并进行Value
,例如从外部进行string
,从而保持类型安全。
您可以通过反射来实现此目的:
public class RowHelper
{
public static Row<object> LoadRow(object o)
{
var type = o.GetType();
return new Row<object>
{
Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null),
Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null)
};
}
}
你可以用以下方式来称呼它:
var d = RowHelper.LoadRow(c);