从类型创建通用变量 - 如何?或者使用带有属性 {} 而不是参数 ( ) 的 Activator.CreateInstance()?

6

我目前正在使用泛型来创建一些动态方法,例如创建对象并为其属性填充值。

是否有办法“动态”创建泛型而不知道类型呢?例如:

List<String> = new List<String>()

是一种预定义的方式,但是...
List<(object.GetType())> = new List<(object.GetType()>()

无法工作...但它能吗?

这个无法工作(是否有类似的方法可行?)

    public T CreateObject<T>(Hashtable values)
    {
        // If it has parameterless constructor (I check this beforehand)
        T obj = (T)Activator.CreateInstance(typeof(T));

        foreach (System.Reflection.PropertyInfo p in typeof(T).GetProperties())
        {
            // Specifically this doesn't work
            var propertyValue = (p.PropertyType)values[p.Name];
            // Should work if T2 is generic
            // var propertyValue = (T2)values[p.Name];

            obj.GetType().GetProperty(p.Name).SetValue(obj, propertyValue, null);
        }
    }

因此,简而言之:如何在不使用泛型的情况下从“类型”创建对象?到目前为止,我只在方法中使用了泛型,但是对于变量是否可以使用相同的方式呢?我必须在方法之前定义一个泛型(T),那么在“创建”它们之前,我能否在变量上执行相同的操作?
...或者如何使用“Activator”创建具有属性而不是参数的对象。就像你在这里做的一样:
// 带参数值
Test t = new Test("Argument1", Argument2);

//使用属性

Test t = new Test { Argument1 = "Hello", Argument2 = 123 };
3个回答

13
你可以使用MakeGenericType
Type openListType = typeof(List<>);
Type genericListType = openListType.MakeGenericType(obj.GetType());
object instance = Activator.CreateInstance(genericListType);

我不想在这种情况下使用“List”,它应该是任何对象。 “Type openListType = typeof(未知类型);” - Deukalion
我不明白这个答案如何解决OP的问题:“使用Activator.CreateInstance()和属性{ }而不是参数( )?” - Avishek

6
你可以使用MakeGenericType方法获取特定类型参数的泛型类型:
var myObjListType = typeof(List<>).MakeGenericType(myObject.GetType());
var myObj = Activator.CreateInstance(myObjListType);
// MyObj will be an Object variable whose instance is a List<type of myObject>

但是假如我创建的对象是一个“String,boolean,int,float......”并不一定是一个类。如果我需要在将对象属性设置为该值之前先对其进行赋值。 - Deukalion
对于值类型,您不需要设置一个值——它们自动具有有效的默认值。例如,布尔类型字段不需要初始化为 false,因为这会自动发生。对于字符串,它们最初是空的。如果您想让它们拥有另一个值,比如 "Fred",您需要将它们的值设置为 "Fred"。不是 Person.FirstName = new String("Fred");,明白吗? - Chris Shain

1
当您使用对象初始化程序时,它只是使用默认构造函数(无参数),然后在对象构造后设置各个属性。
上面的代码很接近 - 但是var在这里不起作用,因为它只是一种编译时类型推断。由于您已经在使用反射,因此可以直接使用System.Object
object propertyValue = values[p.Name];

SetValue 调用与 System.Object 配合使用时可以正常工作。


那么我该如何使用 Activator.CreateInstance 并以“对象初始化器”作为参数?我得到一个错误,提示“没有为该对象定义无参数的构造函数”。我尝试添加值的属性类型有:String、Double、枚举和布尔。它在“String”类型上失败了。它没有无参数的构造函数,所以我无法创建一个字符串并向其添加值,但这怎么可能呢?因为我可以定义:String str; 或 String str = "This is a string"; - Deukalion
@Deukalion 你正在生成的类型没有无参构造函数 - 因此你不能使用这种技术。 - Reed Copsey
String str = "Foo"; 语法是 C# 语言的特性,而不是 CLR 的特性。 - Reed Copsey
我提出的问题标签包括"C#"。 - Deukalion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接