У меня есть два общих интерфейсы, как эти:Кастинг в общий интерфейс с параметром динамического типа
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>
и т.д.
Глядя на его код, и пытается восстановить его, но с вызовом Виндзор контейнера вместо локатора службы, я не могу понять почему его код работает, а мой нет.
Side Примечание: вместо "да, все общественное" может быть лучше, чтобы показать правильный код, как 'общественного BarWrapper (...' –
класс BarWrapper {BarWrapper(); ...} вы уверены, что создатель public? –
Вы пытались получить неотражающую версию 'GetBarFor' для работы в первую очередь? (Укажите тип вместо' foo.GetType() 'и получите его для компиляции/запуска) –