2014-10-24 1 views
3

У меня есть два общих интерфейсы, как эти:Кастинг в общий интерфейс с параметром динамического типа

public interface IFoo<T> { } 
public interface IBar<TFoo, T> where TFoo : Foo<T> { 
    T Qux(TFoo foo); 
} 

IFoo<T> имеет кучу реализаций, каждые с реализацией согласования IBar<S,T>, зарегистрированной в моем контейнере IoC (который бывает Castle.Windsor).

Теперь я хочу создать метод, который на основе аргумента некоторого типа, который реализует IFoo<T>, возвращает соответствующий IBar<IFoo<T>,T> от Windsor. Наивная реализация выглядит следующим образом:

public IBar<TFoo,T> GetBarFor(IFoo<T> foo) where TFoo : IFoo<T> 
{ 
    return container.Resolve<IBar<TFoo,T>>(); 
} 

Однако в коде вызова, не имеют конкретно напечатал Foo<T> - просто IFoo<T>:

public T DoStuffWithStuff<T>(IFoo<T> foo) 
{ 
    var bar = GetBarFor(foo); 
    return bar.Qux(foo); 
} 

и в этом вызове, компилятор не удалось вывести параметры типа (в частности, я думаю, TFoo), поэтому мне нужно сделать другой подход.

Я попытался решить тип с необщей версией Resolve(), но я не могу получить право типа возвращаемого значения:

public AbstractBar<T> GetBarFor(IFoo<T> foo) where TFoo : IFoo<T> 
{ 
    var barType = typeof(IBar<,>).MakeGenericType(foo.GetType(),typeof(T)); 
    var bar = container.Resolve(barType); // bar is now a System.Object 

    var wrapperType = typeof(BarWrapper<,>).MakeGenericType(foo.GetType(), typeof(T)); 
    var wrapper = Activator.CreateInstance(wrapperType, bar); 

    return (AbstractBar<T>)wrapper; 
} 

с

public abstract class AbstractBar<T> { public abstract T Qux(IFoo<T> foo); } 

public class BarWrapper<TFoo, T> : AbstractBar<T> where TFoo : IFoo<T> 
{ 
    private IBar<TFoo,T> _inner; 
    public BarWrapper(IBar<TFoo,T> inner) { _inner = inner; } 

    public T Qux(IFoo<T> foo) { return _inner.Qux((TFoo)foo); } 
} 

, но я держу получая исключения в вызове Activator.CreateInstance, говоря, что конструктор для BarWrapper не найден (да, все public).

Есть ли способ получить звонок в DoStuffWithStuff выше, работая именно для этой подписи (т. Е. Я не могу отложить какие-либо более конкретные генерики от вызывающего кода)?


Сноска: Я видел последний образец работы, в Jimmie Bogard's MediatR implementation of the mediator pattern, а на самом деле то, что я пытаюсь достичь здесь очень похожая реализация, которая не опирается на общий Service Locator, но скорее идет прямо к нашему контейнеру IoC. В контексте IFoo<T> действительно IRequest<out TResponse>, IBar<TFoo, T> действительно IRequestHandler<in TRequest, out TResponse> и т.д.

Глядя на его код, и пытается восстановить его, но с вызовом Виндзор контейнера вместо локатора службы, я не могу понять почему его код работает, а мой нет.

+0

Side Примечание: вместо "да, все общественное" может быть лучше, чтобы показать правильный код, как 'общественного BarWrapper (...' –

+1

класс BarWrapper {BarWrapper(); ...} вы уверены, что создатель public? –

+0

Вы пытались получить неотражающую версию 'GetBarFor' для работы в первую очередь? (Укажите тип вместо' foo.GetType() 'и получите его для компиляции/запуска) –

ответ

0

Неподтвержденный, но вам нужно использовать отражение, чтобы связать тип с информацией о методе родового, который вы хотите выполнить.

 var wrapperType = typeof(BarWrapper<,>).MakeGenericType(foo.GetType(), typeof(T)); 

     MethodInfo TempMethodInfo = typeof(MYClass).GetMethod("DoStuffWithStuff")   

     MethodInfo GenericParam = TempMethodinfo.MakeGenericMethod(T); 

     var Formatter = Delegate.CreateDelegate(wrapperType , GenericParam); 
0

Вы можете использовать старое старое ключевое слово dynamic.

По существу это позволяет времени выполнения определять правильные типы.

IBar<TFoo,T> GetBarFor<TFoo, T>(TFoo dummy, IFoo<T> secondDummy) 
    where TFoo : IFoo<T> 
{ 
    return container.Resolve<IBar<TFoo, T>>(); 
} 

и использование GetBarFor:

GetBarFor((dynamic)foo, (dynamic)foo); 
Смежные вопросы