13

我遇到了这个问题,我正在使用反射从类中提取属性,但问题是反射将它们作为对象返回,我无法将其转换为我的实际类型。

举个例子,如果这是一个类:

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

我错过了什么?

4

3 回答 3

6

使用dynamic而不是object强制运行时真实类型检查:

var c = (dynamic)a;
var d = (Row<object>)c; // Works fine

它会打电话给你的Row<T> -> Row<object>演员。

于 2013-08-29T08:30:48.057 回答
4

这里的问题是,除非在您尝试转换的值的静态类型上定义了转换运算符,否则转换不会寻找转换运算符。c在您的示例中, isobject的静态类型object既不派生自也不具有转换运算符 to Row<object>,从而导致运行时异常。

看起来这个问题可以通过更好的设计轻松回避。

您想将任何类型的Row<T>视为 aRow<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>类型RowRow<object>NameValueValue
  • 设置器Row.Value受到保护,因此您不能从外部投射和制作例如 a ,Row<int>从而保持类型安全。RowValuestring
于 2013-08-29T09:06:56.040 回答
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);
于 2013-08-29T08:39:24.410 回答