Generics with contravariant type parameters and a Unity container

I have an interface with a contravariant type parameter like IFoo :

 interface IFoo<in T> {} 

Now I have three classes:

 class B {} class D : B {} class Foo : IFoo<B> {} 

If I register them this way

 container.RegisterType<IFoo<B>, Foo>(); 

... then try to allow IFoo<D> , it fails because I really have not registered IFoo<D> or IFoo<> , This is clear.

My current solution is simply iterating through Registrations , find the registration in which RegisteredType can be assigned from an allow type ( IFoo<D> in my case), then enable its type MappedToType .

The question is simple: is there a better way to do this? Any advice would be appreciated.

Thanks.

EDIT:

A bit more context.

I have some kind of cartographer.

 IMapper<in TSource, in TDest> : IMapper // IMapper is non-generic { void Map(TSource source, TDest dest); } 

And I want to register only the base mapper (where TSource is IEnumerable<T> ) and be able to enable this handler for every type that implements IEnumerable<T> , for example, for T[] :

 object source = GetSource(); // runtime type is T[] object dest = GetDest(); Type mapperType = typeof(IMapper<,>).MakeGenericType(source.GetType(), dest.GetType()); IMapper mapper = (IMapper) container.Resolve(mapperType); mapper.Map(source, dest); 

And yes, I'm only interested in Unity / C # based approaches ...

+6
source share
1 answer

It seems you want to allow the same Mapper every time. If this is correct, and IEnumerable <> is the only interface your mapper should handle, then your approach seems a bit overkill.

I would try to register the cartuper using not generic IEnumerable() , not IEnumerable<T> ( container.RegisterType<IFoo<IEnumerable>, Foo>(); ). If I remember correctly, a generic IEnumerable<T> can be passed to a non-generic IEnumerable() parameter, so you don't have to worry about which parameter parameter is passed. Therefore, when you go to allow your cartographer, you don’t even need to check the type, just enable IMapper<IEnumerable> .

The following code compiled:

 [TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { IEnumerable<int> coll = new int[0]; IEnumerable coll2 = coll; var blah = new Test<IEnumerable<int>>(); } } public interface ITest<in T> where T : IEnumerable { } public class Test<T> : ITest<T> where T : IEnumerable { } 

If you need to get different implementations of IMapper , then this is another story. In this case, you need to register each implementation.

0
source

Source: https://habr.com/ru/post/945719/


All Articles