Dynamically creating a new instance of IList's type

19,843

Solution 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);
    }

Solution 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.

Solution 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.

Solution 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.

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();
}

Solution 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 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" } );
Share:
19,843
user48408
Author by

user48408

Updated on June 04, 2022

Comments

  • user48408
    user48408 almost 2 years

    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?

    So at any one time I might be processing

    IList<Customer> l;
    

    and I'd like to create a new instance of 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

  • Konrad Rudolph
    Konrad Rudolph about 15 years
    This code doesn't work, and there's nothing similar to achieve this effect.
  • Adam Ralph
    Adam Ralph about 15 years
    Oops, you are correct, have edited the post accordingly. Thanks
  • user48408
    user48408 about 15 years
    The problem here is that type(s) is/are in a different assembly so i don't believe i can call Activator.CreateInstance
  • Konrad Rudolph
    Konrad Rudolph about 15 years
    As long as the assembly is properly loaded, this shouldn't be a problem.
  • user48408
    user48408 about 15 years
    This looks good. In terms of usage. I have an arrayList of IList's which i'm processing in a foreach. So foreach(IList l in arrayOfILists) { Process(l, 0, "None"); } isn't going to compile which being new to generics i don't see why not (?)
  • Adam Ralph
    Adam Ralph about 15 years
    So that means you want to act on a non-generic IList? In your question you said that you want to act on a generic IList<T> giving IList<Customer> as an example.