zoukankan      html  css  js  c++  java
  • IoC之AutoFac(一)——简单使用和组件注册

    阅读目录


    一、AutoFac简单使用

    复制代码
     1 namespace AutofacDemo
     2 {
     3     class Program
     4     {
     5         //用于存储容器的属性
     6         private static IContainer Container { get; set; }
     7         static void Main(string[] args)
     8         {
     9             //获取容器
    10             var builder = new ContainerBuilder();
    11             //注册组件(类),并公开服务(接口)
    12             builder.RegisterType<ConsoleOutput>().As<IOutput>();
    13             builder.RegisterType<TodayWriter>().As<IDateWriter>();
    14             //存储容器
    15             Container = builder.Build();
    16 
    17             WriteDate();//输出当前的日期
    18         }
    19         public static void WriteDate()
    20         {
    21             using (var scope=Container.BeginLifetimeScope())
    22             {
    23                 //解析组件(功能类似于new一个IDateWriter的实现类)
    24                 var writer = scope.Resolve<IDateWriter>();
    25                 writer.WriteDate();
    26             }
    27         }
    28     }
    29     //输出功能接口
    30     public interface IOutput
    31     {
    32         void Write(string content);
    33     }
    34    //控制台输出类
    35     public class ConsoleOutput : IOutput
    36     {
    37         public void Write(string content)
    38         {
    39             Console.WriteLine(content);
    40         }
    41     }
    42     //输出日期的接口
    43     public interface IDateWriter
    44     {
    45         void WriteDate();
    46     }
    47    
    48    //输出今天日期的类
    49     public class TodayWriter : IDateWriter
    50     {
    51         private IOutput _output;//输出日期的类依赖IOutput
    52         public TodayWriter(IOutput output)
    53         {
    54             this._output = output;
    55         }
    56         public void WriteDate()
    57         {
    58             this._output.Write(DateTime.Today.ToShortDateString());
    59         }
    60     }
    61 }
    复制代码

    应用程序执行过程:

      “WriteDate”方法向Autofac询问IDateWriter。

      Autofac看到IDateWriter映射到TodayWriter,所以开始创建一个TodayWriter。

      Autofac认为TodayWriter在其构造函数中需要一个IOutput。

      Autofac看到IOutput映射到ConsoleOutput,所以创建一个新的ConsoleOutput实例。

      Autofac使用新的ConsoleOutput实例来完成TodayWriter的构建。

      Autofac将“WriteDate”的完全构建的TodayWriter返回给消费者。

      之后,如果您希望应用程序编写不同的日期,则可以实现不同的IDateWriter,然后在应用程序启动时更改注册。你不必改变任何其他类。 这样就实现了反转控制!


    二、注册

          使用Autofac 注册组件的任务是:通过创建一个ContainerBuilder并且告知builder 哪些组件公开哪些服务。

    2.1 注册方式

    复制代码
     1  // 创建组件/服务注册的容器
     2             var builder = new ContainerBuilder();
     3 
     5             ////----------------------一、反射组件----------------////
     6             // 反射组件方法1---通过类型注册
     7             builder.RegisterType<ConsoleOutput>().As<IOutput>();
     8             // 反射组件方法2---通过构造函数注册
     9             builder.RegisterType<TodayWriter>()
    10                    .UsingConstructor(typeof(IOutput)).As<IDateWriter>();
    11             
    12      
    13 
    14             ////--------------------二、实例组件----------------------////
    15             // 注册创建的对象实例,把该实例作为一个服务
    16             var output = new ConsoleOutput();
    17             builder.RegisterInstance(output).As<IOutput>();
    18             //不影响系统中原有的单例
    19             builder.RegisterInstance(MySingleton.GetInstance()).ExternallyOwned();  
    20 
    21             
    22 
    23             ////------------------三、Lambda表达式组件---------------////
    24             //参数c是组件上下文(一个IComponentContext对象) ,此处该组件被创建。您可以使用它来解析来自于容器的其他组件,从而帮助你创建组件。
    25 
    26             builder.Register(c => new TodayWriter(c.Resolve<IOutput>())).As<IDateWriter>();
    27 
    28             //分离组件创建最大的好处就是具体类型可以变化
    29             //一个组件分离的Demo:注册一个信用卡组件
    30             builder.Register<CreditCard>(
    31                 (c, p) =>
    32                 {
    33                     var accountId = p.Named<string>("accountId");
    34                     if (accountId.StartsWith("9"))
    35                     {
    36                         return new GoldCard(accountId);
    37                     }
    38                     else
    39                     {
    40                         return new StandardCard(accountId);
    41                     }
    42                 });
    43             //根据参数不同获取不同种类的信用卡类实例
    44             var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));
    45 
    46 
    47             ////-------------------------四、泛型注册------------------////
    48             //泛型注册,可以通过容器返回List<T> 如:List<string>,List<int>等等
    49             builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>)).InstancePerLifetimeScope();
    50             using (IContainer container = builder.Build())
    51             {
    52                 IList<string> ListString = container.Resolve<IList<string>>();
    53             }
    54 
    55 
    56             ////-----------------------五、服务与组件-------------------////
    57             builder.RegisterType<ConsoleLogger>();//默认把注册类型作为公开服务
    58             builder.RegisterType<ConsoleLogger>().As<ILogger>().As<IMyLogger>();//可以公开任意多个服务,但是默认的注册类型会被覆盖
    59             builder.RegisterType<ConsoleLogger>().AsSelf().As<ILogger>();//加上AsSelf()默认的注册类型不会被覆盖
    60             //当公开的服务重名时,服务使用的默认组件是后注册的那个
    61             builder.Register<ConsoleLogger>().As<ILogger>();
    62             builder.Register<FileLogger>().As<ILogger>();//默认使用后注册的FileLogger
    63             //阻止该默认行为,使用builder.Register<FileLogger>().As<ILogger>().PreserveExistingDefaults(),这样不会覆盖以前注册的组件
    64 
    65 
    66             ////-----------六、条件注册(IfNotRegistered,OnlyIf)-------////
    67             //HandlerC不会被注册
    68             builder.RegisterType<HandlerA>()
    69                     .AsSelf()
    70                     .As<IHandler>()
    71                     .IfNotRegistered(typeof(HandlerB));
    72             builder.RegisterType<HandlerB>()
    73                    .AsSelf()
    74                    .As<IHandler>();
    75             builder.RegisterType<HandlerC>()
    76                    .AsSelf()
    77                    .As<IHandler>()
    78                    .IfNotRegistered(typeof(HandlerB));
    79 
    80             //只有IService和HandlerB都注册时,才会去注册Manager
    81             builder.RegisterType<Manager>()
    82                    .As<IManager>()
    83                    .OnlyIf(reg =>
    84                      reg.IsRegistered(new TypedService(typeof(IService))) &&
    85                      reg.IsRegistered(new TypedService(typeof(HandlerB))));
    86 
    87 
    88             // 编译容器完成注册且准备对象解析
    89              Container = builder.Build();
    90 
    91             // 现在你可以使用 Autofac 解析服务. 例如,这行将执行注册的lambda表达式对于 IConfigReader 服务.
    92              using (var scope = Container.BeginLifetimeScope())
    93              {
    94                  var writer = Container.Resolve<IOutput>();
    95                  var dataWriter = Container.Resolve<IDateWriter>();
    96                  writer.Write("111");//输出111
    97                  dataWriter.WriteDate();//输出当前日期
    98                  Console.ReadKey();
    99              }
    复制代码

    2.2 带参数注册

    1、参数类型

      Autofac支持的参数类型有三种:

        NamedParameter - 通过名称匹配目标参数

        TypedParameter - 通过类型匹配目标参数(需要精确匹配类型)

        ResolvedParameter - 灵活的参数匹配

      例子:一个读取配置文件的类,构造器需要传入参数:节点名称

    复制代码
    1 public class ConfigReader : IConfigReader
    2     {
    3         public ConfigReader(string configSectionName)
    4         {
    5             // 存储配置的节点名称
    6         }
    7 
    8         // ...读取基于节点名称的配置
    9     }
    复制代码

    2、反射组件参数

    Parameters with Reflection Components----注册时传入

    复制代码
     1 // 使用一个命名参数:
     2 builder.RegisterType<ConfigReader>()
     3        .As<IConfigReader>()
     4        .WithParameter("configSectionName", "mySectionName");
     5 
     6 // 使用一个类型参数:
     7 builder.RegisterType<ConfigReader>()
     8        .As<IConfigReader>()
     9        .WithParameter(new TypedParameter(typeof(string), "mySectionName"));
    10 
    11 // 使用一个解析参数:
    12 builder.RegisterType<ConfigReader>()
    13        .As<IConfigReader>()
    14        .WithParameter(
    15          new ResolvedParameter(
    16            (pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "configSectionName",
    17            (pi, ctx) => "mySectionName"));
    复制代码

    3、Lambda表达式组件参数

    Parameters with Lambda Expression Components----解析时传入

      在组件注册表达式中,你可以通过改变委托签名使用传入参数进行注册,代替仅仅接收一个IComponentContext参数,一个IComponentContext 和 IEnumerable<Parameter>参数:
    1 builder.Register((c, p) =>
    2                  new ConfigReader(p.Named<string>("configSectionName")))
    3        .As<IConfigReader>();

     当你解析参数时,你的lambda将使用这些参数来传入值:

     var reader = scope.Resolve<IConfigReader>(new NamedParameter("configSectionName", "mySectionName"));

     参考文章:

      1、https://blog.csdn.net/chiyueqi/article/details/52446569

      2、http://www.yuanjiaocheng.net/Autofac/register-parameters.html

  • 相关阅读:
    怎么防止重复提交
    如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?
    什么是 JavaConfig?
    Spring Boot 有哪些优点?
    GBK和GB2312编码
    2.补充:计算机表示的单位:
    python中字符串的编码和解码
    Spring Boot 有哪些优点?
    Maven的工程类型有哪些?
    Maven仓库是什么
  • 原文地址:https://www.cnblogs.com/Alex80/p/10703094.html
Copyright © 2011-2022 走看看