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

时间:2014-03-21 13:23:44

标签: c# generics dependency-injection autofac

我正在尝试通过像这样的构造函数注入一个开放泛型的委托

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

并注册类似

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

我找不到任何这样的API帮助文档。

我可以使用类似的注册,但不涉及泛型。

1 个答案:

答案 0 :(得分:9)

您尝试实现的功能似乎是一种非常实用的方法,在F#等函数式语言中运行良好,但.NET的大多数DI容器都是针对面向对象的语言而构建的,它们本质上是面向类型的,而不是委托或函数导向。您要做的事情是,使用Autofac或其他任何DI容器都无法轻松完成。

即使Autofac能够将泛型方法映射到Func委托,您仍然需要相当多的反射来注册它。例如,这个假设的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)));
}

为了实现这一点,Autofac不仅必须能够与代表合作,而且还能够理解部分开放泛型类型(您的Func<string, IQuery<T>>是部分开放式的)。

因此,您可能希望回到更面向对象的方法,并定义一个描述您的抽象的清晰界面,而不是这样做:

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

您的实施可能如下所示:

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

此接口实现对可以按如下方式注册:

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

您的消费者可以依赖IQueryFactory<T>

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