简体   繁体   English

Autofac。 如何在构造函数中注入一个开放的Generic Delegate

[英]Autofac. How to inject a open Generic Delegate in constructor

I am trying to inject a delegate with open generic through constructor like this 我试图通过像这样的构造函数注入一个开放泛型的委托

protected AQuery(Func<string, IQuery<T>> getQuery)
{
    query = getQuery("contextName");
}

And Register something like 并注册类似的东西

builder
   .Register<Func<string, IQuery<T>>>(
       c => ctx => 
       new Query(c.ResolveNamed<IDbContext>(ctx)));

I could not find any API help documentation for something like this. 我找不到任何这样的API帮助文档。

I was able to use similar registration where generics are not involved. 我能够使用类似的注册,其中不涉及泛型。

What you're trying to achieve seems a very functional approach that works great in functional languages like F#, but most DI containers for .NET are built for object oriented languages and they are inherently type oriented, not delegate or function oriented. 您正在尝试实现的功能似乎是一种非常实用的方法,在F#等函数式语言中运行良好,但.NET的大多数DI容器都是针对面向对象的语言构建的,它们本质上是面向类型的,而不是委托或面向函数。 What you are trying to do, can't be done easily with Autofac, or any other DI container for that matter. 您要做的事情,使用Autofac或任何其他DI容器无法轻松完成。

And even if Autofac was able to map generic methods to Func delegates, you still needed a fair amount of reflection to register this. 即使Autofac能够将泛型方法映射到Func委托,您仍然需要相当多的反射来注册它。 For instance this hypothetical RegisterGenericFunc method: 例如,这个假设的RegisterGenericFunc方法:

builder.RegisterGenericFunc(
    typeof(Func<,>).MakeGenericType(typeof(string), typeof(IQuery<>)),
    typeof(Bootstrapper).GetMethod("QueryFuncFactory"));

public static Func<string, IQuery<T>> QueryFuncFactory<T>(IComponentContext c) {
    return ctx => new Query(c.ResolveNamed<IDbContext>(ctx)));
}

For this to work though, Autofac must not only be able to work with delegates, but also be able to understand partial open-generic types (your Func<string, IQuery<T>> is partial open-generic). 为了实现这一点,Autofac不仅必须能够与委托一起工作,而且还能够理解部分开放泛型类型(您的Func<string, IQuery<T>>是部分开放泛型)。

So instead of doing this, you might want to fall back to a more object oriented approach and define a clear interface that describes your abstraction: 因此,您可能希望回到更面向对象的方法,并定义一个描述您的抽象的清晰界面,而不是这样做:

public interface IQueryFactory<T> {
     IQuery<T> CreateQuery(string context);
}

And your implementation could look like this: 您的实现可能如下所示:

public class AutofacQueryFactory<T> : IQueryFactory<T> {
     private readonly IComponentContext c;

     public AutofacQueryFactory(IComponentContext c) {
         this.c= c;
     }

     public IQuery<T> CreateQuery(string context) {
         return new Query<T>(c.ResolveNamed<IDbContext>(context));
     }
}

This interface-implementation pair can be registered as follows: 此接口实现对可以注册如下:

build.RegisterGeneric(typeof(AutofacQueryFactory<>)).As(typeof(IQueryFactory<>);

And your consumers can depend on IQueryFactory<T> : 您的消费者可以依赖IQueryFactory<T>

protected AQuery(IQueryFactory<T> getQuery)
{
    query = getQuery.CreateQuery("contextName");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM