Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting List<object> to List<T> at runtime

I 'm trying to build a DI container and I 've stumbled on to the following problem: I have a method that retrieves a list of registered instances for a given type and I want to use that to inject IEnumerable<T> properties in a given object. An example of what I am trying to achieve would be the following:

class A { public IList<IExample> Objects { get; set; } }
class B: IExample {}
class C: IExample {}
Container.Register<IExample>(new B());
Container.Register<IExample>(new C());
var obj = new A();
Container.Inject(A);
Debug.Assert(A.Objects != null && A.Objects.Count == 2);

My Retrieve method returns an IList<object>, mainly because I have no type information at that moment, so I am attempting to convert that list into a List<T> at injection time. Here is a succint form of the methods doing the work:

public virtual IList<object> Retrieve(Type type)
{
    var instances = Registry[type];
    foreach(var instance in instances) 
        Inject(type, instance); // omitted
    return instances;
}

public virtual void Inject<T>(T instance)
{
    var properties = typeof (T).GetProperties();
    foreach (var propertyInfo in properties)
    {
      var propertyType = propertyInfo.PropertyType;
      if (!IsIEnumerable(propertyType)) continue;
      var genericType = propertyType.GetGenericArguments()[0];
      propertyInfo.SetValue(instance, 
          GetListType(genericType, Retrieve(genericType)), null);
    }
}

protected virtual object GetListType(Type type, IEnumerable<object> items)
{
    return items.Select(item => Convert.ChangeType(item, type)).ToList();
}

The code returns the error: System.InvalidCastException : Object must implement IConvertible. Sadly, I don't know how to proceed from here. Perhaps I am doing this all wrong. I 've thought of using generics or injecting multiple properties by hand, but I'd really like to not have to do that.

Thanks in advance for any help or ideas.

like image 900
Ioannis Karadimas Avatar asked Aug 15 '12 07:08

Ioannis Karadimas


People also ask

Is ArrayList a subtype of List?

So ArrayList<String> is a subtype of List<String>, which is a subtype of Collection<String>. So long as you do not vary the type argument, the subtyping relationship is preserved between the types.

Is String a subtype of object?

String is a subtype of Object , because the String class is a subclass of the Object class. int is not a subtype of Object , because none of Java's primitive types are subtypes of any reference type.


1 Answers

You could create a generic list like this:

public virtual IList Retrieve(Type type)
{
  // ...
  listType = typeof(List<>).MakeGenericType(new Type[] { type });
  IList list = (IList)Activator.CreateInstance(listType);
  // ...
  return list
}

this list can be casted to IList<T>, because it is one.

You could consider to use IEnumerable and Cast<T>, but then you don't have an instance of a list. I don'^t know how important it is to have one.

like image 112
Stefan Steinegger Avatar answered Oct 23 '22 12:10

Stefan Steinegger