6

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.


In case anyone else wants to know the answer to this, I managed to sort this issue out by recompiling Cordova/Phonegap (1.7.0 but 2.0 should be similar) with a tweak.

To tweak it I modified CDVSound.m, changing line 482 to

[self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];

And re-compiled and then used in my project.

4

1 に答える 1

9

次のような一般的なリストを作成できます。

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

このリストは にキャストできますIList<T>。これは 1 つだからです。

IEnumerableと の使用を検討できCast<T>ますが、リストのインスタンスがありません。持っていることがどれほど重要かわかりません。

于 2012-08-15T08:13:46.577 に答える