代码之家  ›  专栏  ›  技术社区  ›  user3643376

Unity ResolveAll泛型接口

  •  2
  • user3643376  · 技术社区  · 9 年前

    我使用的是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<>));
    

    thows此错误:

    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 回复  |  直到 9 年前
        1
  •  4
  •   Scott Chamberlain    9 年前

    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> ISample<string> object A. List<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);
    }
    

    附笔。 只是为了弄清楚内置的 全部解析 基本上

    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
  •  0
  •   Jeff Siver    9 年前

    ISample<>不是Unity的有效类型;您不能注册它,也不能使用ResolveAll获取使用它的所有类型。如果您查看ResolveAll返回的内容,这有助于说明问题。在这种情况下,它将返回IEnumerable>这是无效的。

    我不太确定你想做什么,所以我不知道该推荐你做什么。

        3
  •  0
  •   user3643376    9 年前

    我已完成创建以下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)
                                             );
    }