Unity ResolveAll Generics Interface

时间:2015-08-21 20:28:38

标签: c# generics unity-container ioc-container

我正在使用Unity IoC,我想注册非泛型类到泛型接口的映射。之后,我想使用ResolveAll方法检索与通用接口相关的所有注册。 这是示例代码:

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<>));
    }
}

在我的代码中这一行:

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

发生此错误:

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)

3 个答案:

答案 0 :(得分:2)

ResolveAll用于查找特定类型的所有命名解析,但它不适用于您正在使用的开放式泛型。要获得你想要的东西,你需要做

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

这将为您提供所有注册的列表。要获取类对象的集合,只需在返回的每个注册上调用Resolve

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

唯一可以同时包含List<T>ISample<int>的{​​{1}} ISample<string>objectList<ISample<object>>不起作用。如果你重写了接口

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

它使代码变得更加简单,并且您在列表中获得了一个更好的对象,可以让您访问ISample中不依赖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。为了明确内置的ResolveAll正在做什么,它基本上是

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)
    }
}

答案 1 :(得分:0)

ISample&LT;&GT;不是Unity的有效类型;您无法注册它,并且您无法使用ResolveAll来获取使用它的所有类型。如果您查看ResolveAll返回的内容,则有助于显示问题。在这种情况下,它将返回IEnumerable&gt;这是无效的。

我不太确定你要做什么,所以我不知道推荐尝试什么。

答案 2 :(得分:0)

我已经完成了在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)
                                         );
}