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 
 4             ///一、反射组件
 5             // 反射组件方法1---通过类型注册
 6             builder.RegisterType<ConsoleLogger>().As<ILogger>();
 7             // 反射组件方法2---通过构造函数注册
 8             builder.RegisterType<MyComponent>()
 9                    .UsingConstructor(typeof(ILogger), typeof(IConfigReader));
10 
11             ///二、实例组件
12             // 注册创建的对象实例,把该实例作为一个服务
13             var output = new StringWriter();
14             builder.RegisterInstance(output).As<TextWriter>();
15 
16             ///三、Lambda表达式组件
17             //参数c是组件上下文(一个IComponentContext对象) ,此处该组件被创建。您可以使用它来解析来自于容器的其他组件,从而帮助你创建组件。
18             builder.Register(c => new A(c.Resolve<B>())).As<IA>();
19 
20             //分离组件创建最大的好处就是具体类型可以变化
21             //注册一个信用卡组件
22             builder.Register<CreditCard>(
23                 (c, p) =>
24                 {
25                     var accountId = p.Named<string>("accountId");
26                     if (accountId.StartsWith("9"))
27                     {
28                         return new GoldCard(accountId);
29                     }
30                     else
31                     {
32                         return new StandardCard(accountId);
33                     }
34              });
35             //根据参数不同获取不同种类的信用卡类实例
36             var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));
37 
38             ///四、服务与组件
39             builder.RegisterType<ConsoleLogger>();//默认把注册类型作为服务
40             builder.RegisterType<ConsoleLogger>().As<ILogger>().As<IMyLogger>();//可以公开任意多个服务,但是默认的注册类型会被覆盖
41             builder.RegisterType<ConsoleLogger>().AsSelf().As<ILogger>();//加上AsSelf()默认的注册类型不会被覆盖
42             //当公开的服务重名时,服务使用的默认组件是后注册的那个
43             builder.Register<ConsoleLogger>().As<ILogger>();
44             builder.Register<FileLogger>().As<ILogger>();//默认使用后注册的FileLogger
45             //阻止该默认行为,使用builder.Register<FileLogger>().As<ILogger>().PreserveExistingDefaults(),这样不会覆盖以前注册的组件
46 
47             ///五、条件注册(IfNotRegistered,OnlyIf)
48             //HandlerC不会被注册
49             builder.RegisterType<HandlerA>()
50                     .AsSelf()
51                     .As<IHandler>()
52                     .IfNotRegistered(typeof(HandlerB));
53             builder.RegisterType<HandlerB>()
54                    .AsSelf()
55                    .As<IHandler>();
56             builder.RegisterType<HandlerC>()
57                    .AsSelf()
58                    .As<IHandler>()
59                    .IfNotRegistered(typeof(HandlerB));
60 
61             //只有IService和HandlerB都注册时,才会去注册Manager
62             builder.RegisterType<Manager>()
63                    .As<IManager>()
64                    .OnlyIf(reg =>
65                      reg.IsRegistered(new TypedService(typeof(IService))) &&
66                      reg.IsRegistered(new TypedService(typeof(HandlerB))));
67             
68 
69             // 编译容器完成注册且准备对象解析
70             var container = builder.Build();
71 
72             // 现在你可以使用 Autofac 解析服务. 例如,这行将执行注册的lambda表达式对于 IConfigReader 服务.
73             using (var scope = container.BeginLifetimeScope())
74             {
75                 var reader = container.Resolve<IConfigReader>();
76             }

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

 

猜你喜欢

转载自www.cnblogs.com/wyy1234/p/9134176.html
今日推荐