2012-08-15 9 views
6

Estoy intentando construir un contenedor DI y he tropezado con el siguiente problema: Tengo un método que recupera una lista de instancias registradas para un tipo determinado y quiero utilízalo para inyectar propiedades IEnumerable<T> en un objeto dado. Un ejemplo de lo que estoy tratando de lograr sería la siguiente:Casting List <object> en la lista <T> en tiempo de ejecución

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

Mi método Retrieve devuelve un IList<object>, sobre todo porque no tengo información de tipo en ese momento, así que estoy tratando de convertir esa lista en un List<T> en el momento de la inyección Aquí es una forma sucinta de los métodos que realizan el trabajo:

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

El código devuelve el error: System.InvalidCastException : Object must implement IConvertible. Lamentablemente, no sé cómo proceder desde aquí. Quizás estoy haciendo todo mal. He pensado en usar genéricos o inyectar múltiples propiedades a mano, pero realmente me gustaría no tener que hacer eso.

Gracias de antemano por cualquier ayuda o idea.

Respuesta

6

Se puede crear una lista genérica de esta manera:

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

esta lista se puede lanzar a IList<T>, porque es uno.

Puede considerar usar IEnumerable y Cast<T>, pero entonces no tiene una instancia de una lista. No sé lo importante que es tener uno.

+0

Eso es algo nuevo. No sabía que podrías crear un tipo genérico directamente. Lo intentaré ahora mismo. –

+0

¡Gracias, funcionó perfectamente! –

Cuestiones relacionadas