Unity ResolveAll Generics Interface

萝らか妹 提交于 2019-12-11 06:07:27

问题


I'm using Unity IoC, I'd like to register mapping of non generic class to generic interface. After that I'd like to use ResolveAll method for retrieve all registration associated to generic interface. This is the sample code:

interface ISample<out T> { }
class Ca : ISample<int> { }
class Cb : ISample<string> { }

class Program
{
    static void Main(string[] args)
    {

        var container = new UnityContainer();
        container.RegisterType<ISample<int>,Ca>();
        container.RegisterType<ISample<string>, Cb>();

        var classList = container.ResolveAll(typeof(ISample<>));
    }
}

in my code this line:

var classList = container.ResolveAll(typeof(ISample<>));

thows this error:

Resolution of the dependency failed, type = "ConsoleApplication1Unity.ISample`1[T][]", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - Could not execute the method because either the method itself or the containing type is not fully instantiated.
----------------------------------------------- At the time of the exception, the container was:
  Resolving ConsoleApplication1Unity.ISample`1[T][],(none)

回答1:


ResolveAll is for finding all named resolutions of a specific type, it does not work with open generics like you are using. To get what you want you would need to do

var registrations = container.Registrations
                   .Where(x => x.RegisteredType.IsGenericType && 
                               x.RegisteredType.GetGenericTypeDefinition() == typeof(ISample<>))
                   .ToList();

That would give you a list of all registrations. To get a collection of the class objects you just need to call Resolve on each registration returned.

var classList = new List<object>();
foreach (var registration in registrations)
{
    var classObject = container.Resolve(registration.RegisteredType, registration.Name);
    classList.Add(classObject);
}

The only type of List<T> that can hold both ISample<int> and ISample<string> is object. A List<ISample<object>> would not work. If you rewrote the interface to be

interface ISample { }
interface ISample<out T> : ISample { }

It makes the code a lot simpler and you get a better object in the list which would let you access the properties and methods of ISample that did not depend on T.

var registrations = container.Registrations
                   .Where(x => typeof(ISample).IsAssignableFrom(x.RegisteredType));

var classList = new List<ISample>();
foreach (var registration in registrations)
{
    var classObject = container.Resolve(registration.RegisteredType, registration.Name);
    classList.Add((ISample)classObject);
}

P.S. Just to make it clear what the built in ResolveAll is doing, it is basically

public IEnumerable<object> ResolveAll(Type t, params ResolverOverride[] resolverOverrides)
{
    var registrations = this.Registrations.Where(x => x.RegisteredType == t);
    foreach (var registration in registrations)
    {
        if(registration.Name != null)
            yield return this.Resolve(registration.RegisteredType, registration.Name, resolverOverrides)
    }
}



回答2:


ISample<> is not a valid type to Unity; you can't register it and you can't use ResolveAll to get all types using it. If you look at what ResolveAll returns, that help show the problem. In this case, it would return an IEnumerable> which is not valid.

I'm not quite sure what you are trying to do so I don't know what to recommend trying.




回答3:


I've completed the task creating following ExtensionMethod

public static IEnumerable<object> ResolveAllOpenGeneric(this IUnityContainer container, Type openGenericType)
{
    if (!openGenericType.IsGenericTypeDefinition)
        throw new ArgumentNullException("argument must be open generic type");

    return container.Registrations.Where(c =>
                                            c.RegisteredType.IsGenericType
                                            && c.RegisteredType.GetGenericTypeDefinition() == openGenericType
                                        )
                                        .Select(r =>
                                                    container.Resolve(r.RegisteredType, r.Name)
                                        );
}

public static IEnumerable<T> ResolveAllOpenGeneric<T>(this IUnityContainer container, Type openGenericType)
{
    if (!openGenericType.IsGenericTypeDefinition)
        throw new ArgumentNullException("argument must be open generic type");

    return container.Registrations.Where(c =>
                                             c.RegisteredType.IsGenericType
                                             && c.RegisteredType.GetGenericTypeDefinition() == openGenericType
                                         )
                                         .Select(r =>
                                                     (T)container.Resolve(r.RegisteredType, r.Name)
                                         );
}


来源:https://stackoverflow.com/questions/32148782/unity-resolveall-generics-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!