1

昨晚我通过示例了解了这个奇妙的转换操作:使用对现有实例的引用来生成某些类型的集合的非常酷的方法。

我的问题是,虽然这在您显式创建实例时有效,但如果您使用激活器从类型实例化,则生成的集合类型不准确。

    class TestCollectionContent
    {
        public int id { get; private set; }
    }

    [Test]
    public void TestListCastCreation()
    {
        var explicitCast = new TestCollectionContent ();    //This casts as TestCollectionContent
        var explicitList = MakeList (explicitCast);         //This casts as List<CommandWithExecute>
        explicitList.Add (new TestCollectionContent ());

        Type clazz = typeof(TestCollectionContent);
        var implicitCast = Activator.CreateInstance (clazz);//This casts as TestCollectionContent
        var implicitList = MakeList (implicitCast);         //This casts as List<object>
        implicitList.Add (new TestCollectionContent ());

        Assert.AreEqual (explicitCast.GetType (), implicitCast.GetType ()); //Succeeds
        Assert.AreEqual (explicitList.GetType (), implicitList.GetType ()); //FAILS!
    }

    public static List<T> MakeList<T>(T itemOftype)
    {
        List<T> newList = new List<T>();
        return newList;
    } 

出于我的目的,必须正确地转换集合。有什么想法吗?

请注意,我将 C# 与 Unity3D 一起使用(它使用类似于 .Net 3.5 的东西)。

4

2 回答 2

1

Activator.CreateInstance总是返回一个object,所以你在使用它时不会从中得到任何静态类型信息。这将使变量implicitCast成为类型,object尽管它的值是更专业的类型。

现在使用泛型时,只考虑可用于静态类型的类型。因此,当传递implicitCast给时MakeList,该方法看到的只是一个object. 因此,该方法将调用 asMakeList<object>并将返回 a List<object>,当然它与 的类型不同explicitList

不幸的是(或幸运的是?)你真的不能做得更好。泛型应该是在静态类型环境中使用的东西,如果您开始动态创建类型,您将失去这种能力。

但是,您也可以Activator.CreateInstance通过执行以下操作来创建列表:

public static IList MakeList(object itemOftype)
{
    Type listType = typeof(List<>).MakeGenericType(itemOfType.GetType());
    return (IList) Activator.CreateInstance(listType);
}

当然,这也只会返回一个对象,因此您必须将其转换为更专业的类型,或者使用非泛型IList接口至少可以访问它。

于 2013-11-01T17:27:26.387 回答
0

这段代码的行为是这样的,因为T是在编译时推断出来的,而不是在运行时推断出来的。由于implicitCast是 类型object,因此它与MakeList<object>.

var implicitList = MakeList (implicitCast); // equivalent to
List<object> implicitList = MakeList<object>(implicitCast);

var explicitList = MakeList (explicitCast); // equivalent to
List<TestCollectionContent> explicitList =
                   MakeList<TestCollectionContent>(explicitCast);

如果希望它使用运行时类型,可以使用反射或dynamic.

于 2013-11-01T17:27:37.363 回答