通过反射和隐式强制转换创建泛型列表

本文关键字:转换 创建 泛型 列表 反射 | 更新日期: 2023-09-27 17:54:42

我的目标是.Net框架的4.0版本。我写了以下简单的代码:

public class A
{
    public A()
    {
    }
}
public class B
{
    public B()
    {
    }
    public static implicit operator A(B b)
    {
        return new A();
    }
}

然后我创建了一个通用列表:

 var mylist = typeof(List<>).MakeGenericType(typeof(A)).GetConstructor(Type.EmptyTypes).Invoke(new object[]{});

当我想添加B的新实例时,以下代码有效:

((IList<A>)mylist).Add(new B());

但是,如果我运行以下代码,则会引发以下异常:

The value "B" is not of type "A" and cannot be used in this generic collection.

参数名称:值

((IList)mylist).Add(new B());

通过反射和隐式强制转换创建泛型列表

当您将类型为B的对象添加到IList<A>时,隐式转换仅发生在第一个Add中。在第二种情况下,您将其添加到非通用IList,这是一个对象集合,当对象实际添加到List<A> 时,隐式转换不会发生并爆炸

即使这样也会失败:

var mylist = new List<A>();
((IList<A>)mylist).Add(new B());
((IList)mylist).Add(new B())

然而,你可以这样做:

((IList)mylist).Add((A)new B());

问题是,当您将列表强制转换为IList<A>并调用Add时,编译器(隐式(将B实例的强制转换添加到A。在第二种情况下,IList只接受Add方法中的objectB是一个对象,因此它不会强制转换为A。因此,当该方法尝试在内部将其添加到底层数据结构时,会引发异常。

你甚至可以通过以下代码进行测试:

var fails = (A) (object) new B();

既然你问如何解决这个问题(尽管我认为在这种情况下没有必要将类型强制转换为IList(,那么在添加它时,你可以直接将B显式强制转换为A。示例:

mylist.Add((A) new B());