我使用Activator.CreateInstance
通过类型变量(在运行时未知)创建对象:
static dynamic CreateFoo( Type t ) =>
Activator.CreateInstance( t );
显然,我还不能正确理解如何使用dynamic
类型,因为这仍然只是返回一个对象。
我需要能够将集合传递给对Activator.CreateInstance
的另一个调用,其中创建的类型可以是List<T>
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要求:
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( ) { }
}
}
发布于 2018-09-12 06:51:41
使用此方法:
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接口的较短版本
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;
}
更接近实际用例:动态列表类型
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;
}
https://stackoverflow.com/questions/52284671
复制相似问题