动态创建IList类型的新实例

时间:2021-10-27 17:00:37

My application is processing IList's. ILists of different user defined types. I'm thinking that i can use reflection to to see what type of object the IList contains and then create a new instance of that type and subsequently add that to the IList itself?

我的申请正在处理IList。不同用户定义类型的IList。我想我可以使用反射来查看IList包含的对象类型,然后创建该类型的新实例,然后将其添加到IList本身?

So at any one time I might be processing

所以在任何时候我都可能正在处理

IList<Customer> l;

and I'd like to create a new instance of Customer

我想创建一个新的Customer实例

Customer c = new Customer(0, "None")

and then add that onto the list

然后将其添加到列表中

l.Add(c);

Obviously doing this dynamically at run-time is the crux of the problem. Hope somebody can give me some pointers. Thanks brendan

显然,在运行时动态执行此操作是问题的关键。希望有人能给我一些指示。谢谢brendan

8 个解决方案

#1


Try this:

    public static void AddNewElement<T>(IList<T> l, int i, string s)
    {
        T obj = (T)Activator.CreateInstance(typeof(T), new object[] { i, s });
        l.Add(obj);
    }

Usage:

    IList<Customer> l = new List<Customer>();
    l.Add(new Customer(1,"Hi there ..."));

    AddNewElement(l, 0, "None");

(EDIT):

Try this then:

然后尝试这个:

    public static void AddNewElement2(IList l, int i, string s)
    {
        if (l == null || l.Count == 0)
            throw new ArgumentNullException();
        object obj = Activator.CreateInstance(l[0].GetType(), new object[] { i, s });
        l.Add(obj);
    }

#2


If you can use a parameterless constructor and set the properties afterwards then you can make your method generic, something like:-

如果你可以使用无参数构造函数并在之后设置属性,那么你可以使你的方法通用,如: -

    void Process<T>(IList<T> list, int x, string y) where T : MyBase, new()
    {
        T t = new T();
        t.X = x;
        t.Y = y;
        list.Add(t);
    }

Where MyBase is the base for your classes which expose the int and string properties. You can use an interface rather than a base class if you want.

其中MyBase是暴露int和string属性的类的基础。如果需要,可以使用接口而不是基类。

#3


You can use the Activator.CreateInstance method to invoke a constructor for a class via its type name (as a string) or an instance of System.Type.

您可以使用Activator.CreateInstance方法通过类型名称(作为字符串)或System.Type的实例来调用类的构造函数。

#4


I think you should change your design. You can use abstract factory pattern. Using reflection would degrade performance.

我想你应该改变你的设计。您可以使用抽象工厂模式。使用反射会降低性能。

Here is code for factory.

这是工厂的代码。

public abstract class MyStore {
    public abstract string Name { get; }
    public abstract void AddItem(int id, string name);
}

You can consider using interface if your abstract class has no code.

如果抽象类没有代码,可以考虑使用接口。

Then create Customer store.

然后创建Customer store。

public class CustomerStore : MyStore, IEnumerable<Customer> {
    List<Customer> list = new List<Customer>();

    public override string Name { get { return "Customer Store"; } }
    public override void AddItem(int id, string name) {
        list.Add(new Customer(id, name));
    }
    public IEnumerator<Customer> GetEnumerator() {
        return list.GetEnumerator();
    }
}

Usage

foreach (MyStore store in List<MyStore>)
    store.AddItem(0, "None");

If you want to consider type of store, use

如果要考虑商店类型,请使用

switch (store.Name) {
case "Customer Store":
    SomeMethod((CustomerStore)store);
    break;
default:
    throw new WhatEverException();
}

#5


You could use the Type.GetGenericArguments method to return the type argument of the generic type IList<T>. Then invoke the appropriate constructor.

您可以使用Type.GetGenericArguments方法返回泛型类型IList 的类型参数。然后调用适当的构造函数。

  Type T = l.GetType ( ).GetGenericArguments ( ) [ 0 ];
  ConstructorInfo ctor = T.GetConstructor (
    new Type [ 2 ] { typeof ( int ), typeof ( string ) } );
  System.Diagnostics.Debug.Assert ( ctor != null );
  object instance = ctor.Invoke (
    new object [ 2 ] { 0, "None" } );

#6


Yes sorry i should have mentioned that the set of objects i will be processing will have a constructor that accepts an int and a string.

是抱歉我应该提到我将要处理的对象集将有一个接受int和字符串的构造函数。

#7


The big problem here is: If you don't know the type, how do you know how to make a new one? Not every type in the world has a constructor that takes an int and a string.

这里的一个大问题是:如果你不知道这种类型,你怎么知道如何制作新的?并非世界上的每个类型都有一个带有int和字符串的构造函数。

#8


The best way to get the type of the IList is to look at the property type of the indexer!

获取IList类型的最佳方法是查看索引器的属性类型!

var collectionType = targetList.GetType().GetProperty("Item").PropertyType;
var constructor = collectionType.GetConstructor(Type.EmptyTypes);
var newInstance = constructor.Invoke(null);

#1


Try this:

    public static void AddNewElement<T>(IList<T> l, int i, string s)
    {
        T obj = (T)Activator.CreateInstance(typeof(T), new object[] { i, s });
        l.Add(obj);
    }

Usage:

    IList<Customer> l = new List<Customer>();
    l.Add(new Customer(1,"Hi there ..."));

    AddNewElement(l, 0, "None");

(EDIT):

Try this then:

然后尝试这个:

    public static void AddNewElement2(IList l, int i, string s)
    {
        if (l == null || l.Count == 0)
            throw new ArgumentNullException();
        object obj = Activator.CreateInstance(l[0].GetType(), new object[] { i, s });
        l.Add(obj);
    }

#2


If you can use a parameterless constructor and set the properties afterwards then you can make your method generic, something like:-

如果你可以使用无参数构造函数并在之后设置属性,那么你可以使你的方法通用,如: -

    void Process<T>(IList<T> list, int x, string y) where T : MyBase, new()
    {
        T t = new T();
        t.X = x;
        t.Y = y;
        list.Add(t);
    }

Where MyBase is the base for your classes which expose the int and string properties. You can use an interface rather than a base class if you want.

其中MyBase是暴露int和string属性的类的基础。如果需要,可以使用接口而不是基类。

#3


You can use the Activator.CreateInstance method to invoke a constructor for a class via its type name (as a string) or an instance of System.Type.

您可以使用Activator.CreateInstance方法通过类型名称(作为字符串)或System.Type的实例来调用类的构造函数。

#4


I think you should change your design. You can use abstract factory pattern. Using reflection would degrade performance.

我想你应该改变你的设计。您可以使用抽象工厂模式。使用反射会降低性能。

Here is code for factory.

这是工厂的代码。

public abstract class MyStore {
    public abstract string Name { get; }
    public abstract void AddItem(int id, string name);
}

You can consider using interface if your abstract class has no code.

如果抽象类没有代码,可以考虑使用接口。

Then create Customer store.

然后创建Customer store。

public class CustomerStore : MyStore, IEnumerable<Customer> {
    List<Customer> list = new List<Customer>();

    public override string Name { get { return "Customer Store"; } }
    public override void AddItem(int id, string name) {
        list.Add(new Customer(id, name));
    }
    public IEnumerator<Customer> GetEnumerator() {
        return list.GetEnumerator();
    }
}

Usage

foreach (MyStore store in List<MyStore>)
    store.AddItem(0, "None");

If you want to consider type of store, use

如果要考虑商店类型,请使用

switch (store.Name) {
case "Customer Store":
    SomeMethod((CustomerStore)store);
    break;
default:
    throw new WhatEverException();
}

#5


You could use the Type.GetGenericArguments method to return the type argument of the generic type IList<T>. Then invoke the appropriate constructor.

您可以使用Type.GetGenericArguments方法返回泛型类型IList 的类型参数。然后调用适当的构造函数。

  Type T = l.GetType ( ).GetGenericArguments ( ) [ 0 ];
  ConstructorInfo ctor = T.GetConstructor (
    new Type [ 2 ] { typeof ( int ), typeof ( string ) } );
  System.Diagnostics.Debug.Assert ( ctor != null );
  object instance = ctor.Invoke (
    new object [ 2 ] { 0, "None" } );

#6


Yes sorry i should have mentioned that the set of objects i will be processing will have a constructor that accepts an int and a string.

是抱歉我应该提到我将要处理的对象集将有一个接受int和字符串的构造函数。

#7


The big problem here is: If you don't know the type, how do you know how to make a new one? Not every type in the world has a constructor that takes an int and a string.

这里的一个大问题是:如果你不知道这种类型,你怎么知道如何制作新的?并非世界上的每个类型都有一个带有int和字符串的构造函数。

#8


The best way to get the type of the IList is to look at the property type of the indexer!

获取IList类型的最佳方法是查看索引器的属性类型!

var collectionType = targetList.GetType().GetProperty("Item").PropertyType;
var constructor = collectionType.GetConstructor(Type.EmptyTypes);
var newInstance = constructor.Invoke(null);