Search code examples
c#genericsunity-container

Is it possible to register a generic interface without specifying generic types in Unity?


Let's say I have the following:

 public interface IDataTranslator<TFrom, TTo>  {
        TTo Translate(TFrom fromObj);
    }

  public class IdentityDataTranslator<T> : IDataTranslator<T, T> {
        public T Translate(T fromObj) {
            return fromObj;
        }
    }

I am looking for a way where I can do:

   IdentityDataTranslator<A> trA = UnityContainer.Resolve<IDataTranslator<A, A>>()
   IdentityDataTranslator<B> trB = UnityContainer.Resolve<IDataTranslator<B, B>>()
   IdentityDataTranslator<C> trc = UnityContainer.Resolve<IDataTranslator<C, C>>()

And for all these resolves (assume I don't know the types of the generics that will be resolved) I would like Unity to return an instance of the IdentityDataTranslator with the appropriate generic. Is there a way to register somehow with Unity to achieve this?


Solution

  • If I right understood your question you can use InjectionFactory to set how to resolve the current type. It looks like this:

        // It's a test implementation of IDataTranslator<From, To>
        public class DataTranslator<TFrom, TTo> : IDataTranslator<TFrom, TTo>
        {
            TTo IDataTranslator<TFrom, TTo>.Translate(TFrom fromObj)
            {
                throw new NotImplementedException();
            }
        }
    
        ...
        var strResolve = "notSameResolve";
        container.RegisterType(typeof(IDataTranslator<,>), typeof(DataTranslator<,>), strResolve);
        container.RegisterType(typeof(IDataTranslator<,>),
            new InjectionFactory(
                (con, type, str) =>
                {
                    var argumets = type.GetGenericArguments();
                    if (argumets[0] != argumets[1])
                    {
                        return con.Resolve(type, strResolve);
                    }
    
                    return con.Resolve(typeof(IdentityDataTranslator<>).MakeGenericType(type.GetGenericArguments()[0]));
                }));
    
        var trA = (IdentityDataTranslator<A>)container.Resolve<IDataTranslator<A, A>>();
        var trAData = (DataTranslator<A, B>)container.Resolve<IDataTranslator<A, B>>();
    

    So if you try to resolve IDataTranslator<A, B> with InjectionFactory that is above, you get a DataTranslator<A, B> and get IdentityDataTranslator<A> when try to resolve IDataTranslator<A, A> with the same arguments.