AutoFac学习笔记

AutoFac注册组件---通过参数值选择具体的实现


官方文档链接:Autofac

1. 通过参数值选择具体的实现

builder.Register<ICreditCard>(
  (c, p) =>
    {
      var accountId = p.Named<string>("accountId");
      if (accountId.StartsWith("9"))
      {
        return new GoldCard(accountId);
      }
      else
      {
        return new StandardCard(accountId);
      }
    });

以上代码实现了在运行时指定具体的注册类型,而不是在配置时期指定,增加了灵活性。

但是这种写法不是最优解,如果申明一个创建ICreditCard实例的委托,和一个委托工厂,语法可以变得更加干净,类型安全。

委托工厂

工厂适配器将容器的实例化特性提供给托管组件,而不是将容器本身暴露给它们。
如果类型T在容器中注册,AutoFac将自动解析对Func<T>的依赖关系,将其作为通过容器创建实例T的工厂。

在使用委托工厂以及使用参数化的Func或者Func<X,Y,T>关系时,应该考虑生命周期范围,如果将对象注册为InstancePerDependency ()在多次调用委托工厂时,都会得到一个新的实例,但如果将对象注册为SingleInstance
则每次调用委托工厂都会得到相同的实例。仅传递不同的参数不会违反对生命周期范围的重视。


以上这一段引用了原文并进行了翻译,为防止翻译出现纰漏 在此附上原文

Lifetime scopes are respected using delegate factories as well as when using Func or the parameterized Func<X,Y,T> relationships. If you register an object as InstancePerDependency() and call the delegate factory multiple times, you'll get a new instance each time. However, if you register an object as SingleInstance() and call the delegate factory to resolve the object more than once, you will get the same object instance every time regardless of the different parameters you pass in. Just passing different parameters will not break the respect for the lifetime scope


通过委托工厂来创建实例

public class Shareholding
{
  public delegate Shareholding Factory(string symbol, uint holding);

  public Shareholding(string symbol, uint holding)
  {
    Symbol = symbol;
    Holding = holding;
  }

  public string Symbol { get; private set; }

  public uint Holding { get; set; }
}

在以上的代码中Shareholdings类声明了一个构造函数,并提供了一个委托类型,此委托类型可以间接创造Shareholdings类,AutoFac利用这个委托类型自动生成一个工厂,并通过容器来访问它来创造实例。

var builder = new ContainerBuilder(); 
builder.RegisterType<Shareholding>(); 
var container = builder.Build();
var shareholdingFactory = container.Resolve<Shareholding.Factory>(); 
var shareholding = shareholdingFactory.Invoke("ABC", 1234);

该工厂是标准委托,可以使用如上所述的Invoke()或函数语法shareholdingFactory("ABC",1234)进行调用。

默认情况下,AutoFac按参数名称将委托的参数与构造函数的参数进行匹配。 如果您使用通用Func类型,则Autofac将切换成按类型去匹配参数。

其他部件也可以使用刚才构建的工厂,代码如下

public class Portfolio
{
  Shareholding.Factory ShareholdingFactory { get; set; }
  IList<Shareholding> _holdings = new List<Shareholding>();

  public Portfolio(Shareholding.Factory shareholdingFactory)
  {
    ShareholdingFactory = shareholdingFactory;
  }

  public void Add(string symbol, uint holding)
  {
    _holdings.Add(ShareholdingFactory(symbol, holding));
  }
}

为了建立连接,Portfolio类需要在容器构建之前注册

使用组件

可以通过从容器请求一个Portfolio实例来使用这些组件,容器会自动匹配Portfolio的构造参数并注入实例:

var portfolio = container.Resolve<Portfolio>();
portfolio.Add("DEF", 4324);
graph TD A[构建Portfolio] --> B(构造函数需要参数:Shareholding.Factory) B --> C(构建Shareholding) C --> A F(容器实例化Portfolio的流程)

根据上文提到的如果您使用通用Func类型,则Autofac将切换成按类型去匹配参数
我们可以使用Func<T>委托来创造工厂,它将通过类型来匹配构造函数的参数。


打工人下班,收假回来继续写


上一篇:翻译:《实用的Python编程》07_05_Decorated_methods


下一篇:R语言动量和马科维茨Markowitz投资组合(Portfolio)模型实现