Go to a generic interface with a dynamic type parameter
I have two common interfaces:
public interface IFoo<T> { }
public interface IBar<TFoo, T> where TFoo : Foo<T> {
T Qux(TFoo foo);
}
IFoo<T>
has a variety of implementations, each with a corresponding implementation IBar<S,T>
registered in my IoC container (which happens to be Castle.Windsor).
Now I want to create a method that, based on an argument of some type that implements IFoo<T>
, returns the corresponding one IBar<IFoo<T>,T>
from Windsor. A naive implementation looks like this:
public IBar<TFoo,T> GetBarFor(IFoo<T> foo) where TFoo : IFoo<T>
{
return container.Resolve<IBar<TFoo,T>>();
}
However, in the calling code, I don't have it specifically printed Foo<T>
- just IFoo<T>
:
public T DoStuffWithStuff<T>(IFoo<T> foo)
{
var bar = GetBarFor(foo);
return bar.Qux(foo);
}
and in this call the compiler cannot infer the type parameters (in particular, I think TFoo
), so I need to take a different approach.
I tried to resolve the non-generic type Resolve()
, but then I can't get the correct return type:
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;
}
from
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); }
}
but I keep getting exceptions from the call Activator.CreateInstance
saying the constructor for BarWrapper
not found (yes, everything is public
).
Is there a good way to get the call in DoStuffWithStuff
above that works exactly for this signature (i.e. I cannot defer any more specific generics from the calling code)?
Footnote: I've seen the latter pattern work, Jimmie Bogard MediatR's implementation of the mediator pattern , and in fact what I'm trying to do here is a very similar implementation that doesn't rely on the Common Service Locator, but rather directly on our IoC container. In context IFoo<T>
really IRequest<out TResponse>
, IBar<TFoo, T>
really IRequestHandler<in TRequest, out TResponse>
, etc.
Looking at his code and trying to recreate it, but with a call to the Windsor container instead of the service locator, I can't figure out why his code works and mine doesn't.
source to share
Untested, but you need to use reflection to later associate the type with information about the generic type method you want to execute.
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);
source to share
You can use the old keyword dynamic
.
Essentially, this allows runtime to determine the correct types.
IBar<TFoo,T> GetBarFor<TFoo, T>(TFoo dummy, IFoo<T> secondDummy)
where TFoo : IFoo<T>
{
return container.Resolve<IBar<TFoo, T>>();
}
and use GetBarFor
:
GetBarFor((dynamic)foo, (dynamic)foo);
source to share