简体   繁体   English

无效的强制转换异常泛型

[英]Invalid cast exception generics

I'm having this issue, I'm using reflection to pull properties from a class but the problem is reflection returns them as an object and I can't get it into my actual type. 我遇到了这个问题,我正在使用反射从类中提取属性,但问题是反射将它们作为对象返回,我无法将其转换为实际类型。

Take for example, if this is the class: 例如,如果这是班级:

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; }
}

Casting from one say Row<bool> to Row<object> works: 从一个人说出Row<bool>Row<object>工作原理:

    var a = new Row<bool>
    {
        Name = "Foo",
        Value = true
    };

    var b = (Row<object>)a; // Works

But when I try to go from object to Row<object> it seems to ignore my explicit operator and throw a System.InvalidCastException: 但是当我尝试从object转到Row<object> ,似乎忽略了我的显式运算符并抛出了System.InvalidCastException:

var c = (object) a; // Simulate getting from reflection

var d = (Row<object>) c; // System.InvalidCastException

What am I missing? 我错过了什么?

Use dynamic instead of object to force runtime real type check: 使用dynamic而不是object来强制运行时实际类型检查:

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

It will call your Row<T> -> Row<object> cast operator. 它将调用Row<T> -> Row<object>强制转换运算符。

The problem here is that casting does not look for a conversion operator unless one is defined on the static type of the value you are trying to cast. 这里的问题是,除非在您尝试强制转换的值的静态类型上定义转换运算符,否则转换不会查找转换运算符。 In your example the static type of c is object and object neither derives from nor has a conversion operator to Row<object> , resulting in the runtime exception. 在您的示例中, c的静态类型是objectobject既不是从Row<object>派生也没有转换运算符,从而导致运行时异常。

It looks like this problem can be easily sidestepped with a better design. 看起来这个问题可以通过更好的设计轻松回避。

You want to treat any type of Row<T> as a Row<object> and the conversion operator does nothing more than work around the fact that these types are not hierarchically related. 您希望将任何类型的Row<T>视为Row<object> ,并且转换运算符只会解决这些类型与层次结构无关的事实。 So why not make them related and avoid the problem in the first place? 那么为什么不让它们相关并首先避免这个问题呢?

For example: 例如:

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; }
    }
}

This seems to do what you want: 这似乎做你想要的:

  • The casting problem is solved because you can now cast any type of Row<T> to the base class Row (which takes over the responsibilities of Row<object> in your initial design) and easily access Name and Value no matter what type the Value is. 铸造问题就解决了,因为你现在可以将任何类型的Row<T>基类Row (其接管的职责Row<object>在初始设计),并方便地访问NameValue ,不管是什么类型的Value是。
  • The Row.Value setter is protected so you cannot cast a Row<int> to Row and make Value eg a string from outside, maintaining type safety. Row.Value setter受到保护,因此您无法将Row<int> Row.ValueRow并从外部生成Value例如string ,从而保持类型安全。

You can accomplish this with reflection: 你可以用反射完成这个:

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)
        };
    }
}

You would call this with: 您可以这样称呼:

var d = RowHelper.LoadRow(c);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM