我遇到了这个问题,我正在使用反射从类中提取属性,但问题是反射将它们作为对象返回,我无法将其转换为实际类型。
例如,如果这是班级:
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
我错过了什么?
答案 0 :(得分:6)
使用dynamic
代替object
强制运行时实际类型检查:
var c = (dynamic)a;
var d = (Row<object>)c; // Works fine
它将调用您的Row<T> -> Row<object>
演员。
答案 1 :(得分:4)
这里的问题是,除非在您尝试强制转换的值的静态类型上定义转换运算符,否则转换不会查找转换运算符。在您的示例中,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>
的职责)并轻松访问Name
和Value
,无论Value
是什么类型。Row.Value
setter受到保护,因此您无法将Row<int>
转换为Row
并将Value
设置为string
。来自外部的{{1}},保持类型安全。答案 2 :(得分:2)
你可以用反射完成这个:
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);