首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使用Activator.CreateInstance在运行时创建T未知的List<T>?

如何使用Activator.CreateInstance在运行时创建T未知的List<T>?
EN

Stack Overflow用户
提问于 2018-09-12 05:50:34
回答 1查看 5K关注 0票数 5

我使用Activator.CreateInstance通过类型变量(在运行时未知)创建对象:

代码语言:javascript
复制
static dynamic CreateFoo( Type t ) =>
    Activator.CreateInstance( t );

显然,我还不能正确理解如何使用dynamic类型,因为这仍然只是返回一个对象。

我需要能够将集合传递给对Activator.CreateInstance的另一个调用,其中创建的类型可以是List<T>

代码语言:javascript
复制
var values = Enumerable.Range( 1, 50 ).Select(
    I => CreateFoo( typeof( Foo ) ) ).ToArray( );
//This will explode.
var foobar = Activator.CreateInstance(
    typeof( List<Foo> ), values );

当上面的代码被调用时,它会爆炸,但会出现以下异常:

我知道它为什么这么做了--当一个列表是用一个类型参数定义的时候,对于一个期望对象的枚举的列表,没有构造函数。

问题是我不能强制转换对象,因为我不知道运行时的类型。Activator.CreateInstance似乎只返回一个对象,这对于List<Foo>来说没问题,因为我将使用依赖对象和属性来设置它们,所以装箱的对象对它们来说是完全合适的,但是在尝试创建列表时会破坏所有东西(可能还会破坏任何其他需要类型参数的构造函数)。

对于我试图在这里完成的工作,正确的方法是什么?

符合Minimal, Complete and Verifiable Example要求:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;

namespace MCVEConsole {
    class Program {
        static int Main( string[ ] args ) {
            var values = Enumerable.Range( 1, 50 ).Select(
                I => CreateFoo( typeof( Foo ) ) ).ToArray( );

            //This will compile, but explode when run.
            var foobar = Activator.CreateInstance(
                typeof( List<Foo> ), values );
            return 1;
        }

        static dynamic CreateFoo( Type t ) =>
            Activator.CreateInstance( t );
    }

    class Foo {
        public Foo( ) { }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-12 06:51:41

使用此方法:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        CreateListFromType(typeof(Foo));
        CreateListFromType(typeof(int));
    }

    static object CreateListFromType(Type t)
    {
        // Create an array of the required type
        Array values = Array.CreateInstance(t, 50);

        // and fill it with values of the required type
        for (int i = 0; i < 50; i++)
        {
            values.SetValue(CreateFooFromType(t), i);
        }

        // Create a list of the required type, passing the values to the constructor
        Type genericListType = typeof(List<>);
        Type concreteListType = genericListType.MakeGenericType(t);

        object list = Activator.CreateInstance(concreteListType, new object[] { values }); 

        // DO something with list which is now an List<t> filled with 50 ts
        return list;
    }


    // Create a value of the required type
    static object CreateFooFromType(Type t)
    {
        return Activator.CreateInstance(t);
    }
}

class Foo
{
    public Foo() { }
}

在这种情况下,不需要使用dynamic。我们可以只使用object作为我们创建的值。非引用类型将使用装箱存储在object中。

为了创建List<>类型,我们可以首先获得泛型类型的表示形式,然后使用它通过MakeGenericType方法创建具体类型。

注意您在创建列表的CreateInstance调用中所犯的错误:

在尝试构造列表时,需要将值数组作为元素嵌入到对象数组中。因此Activator将在List<t>中查找需要IEnumerable<t>类型单个参数的构造函数。

按照您编写它的方式,Activator查找一个构造函数,该构造函数需要50个参数,每个参数都是t类型。

使用非通用IList接口的较短版本

代码语言:javascript
复制
using System.Collections;

static IList CreateListFromType(Type t)
{
    // Create a list of the required type and cast to IList
    Type genericListType = typeof(List<>);
    Type concreteListType = genericListType.MakeGenericType(t);
    IList list = Activator.CreateInstance(concreteListType) as IList;

    // Add values
    for (int i = 0; i < 50; i++)
    {
        list.Add(CreateFooFromType(t));
    }

    // DO something with list which is now an List<t> filled with 50 ts
    return list;
}

更接近实际用例:动态列表类型

代码语言:javascript
复制
static void Main(string[] args)
{
    CreateListFromType(typeof(List<Foo>));
    CreateListFromType(typeof(ObservableCollection<int>));
}

static IList CreateListFromType(Type listType)
{
    // Check we have a type that implements IList
    Type iListType = typeof(IList);
    if (!listType.GetInterfaces().Contains(iListType))
    {
        throw new ArgumentException("No IList", nameof(listType));
    }

    // Check we have a a generic type parameter and get it
    Type elementType = listType.GenericTypeArguments.FirstOrDefault();
    if (elementType == null)
    {
        throw new ArgumentException("No Element Type", nameof(listType));
    }

    // Create a list of the required type and cast to IList
    IList list = Activator.CreateInstance(listType) as IList;

    // Add values
    for (int i = 0; i < 50; i++)
    {
        list.Add(CreateFooFromType(elementType));
    }

    // DO something with list which is now a filled object of type listType 
    return list;
}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52284671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档