第二节 Autofac的注册

A) autofac的基本注册

您通过创建ContainerBuilder,通知构建器哪些组件,暴露哪些服务,来向Autofac注册组件。
注册的方式有三种:

  1. 通过反射创建(通过注册一个特定的.NET类型或开放的泛型)
  2. 通过提供现成的实例(您创建的对象的实例)
  3. 通过lambda表达式(执行实例化您的对象的匿名函数)

1.反射组件-按类型注册
当使用基于反射的组件时,Autofac会自动为您的类使用能够从容器获取的最多参数的构造函数。

using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{
    public interface IOutput
    {
        void Show();
    } 
    public class ConsoleOutput : IOutput
    {
        public void Show()
        {
            Console.WriteLine("Show");
        }
    }         
    public interface IInput
    {
        void Get();
    }
    public class ConsoleInput : IInput
    {
        public void Get()
        {
            Console.WriteLine("Get");
        }
    }
    
    public class Component
    {
        private IOutput output;
        private IInput input;
        public Component(IOutput output)
        {
            this.output = output;
        }
        public Component(IOutput output,IInput input)
        {
            this.output = output;
            this.input = input;
        }
        public void Implement()
        {
            output?.Show();
            input?.Get();
        }
    }   
}

若IInput和IOutput服务都注册,则Component会自动选择两个参数的构造函数,反之选择一个参数的构造函数

namespace ConsoleApp1
{
	class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();
						
            containerBuilder.RegisterType<ConsoleInput>().As<IInput>();
            containerBuilder.RegisterType<ConsoleOutput>().As<IOutput>();
            containerBuilder.RegisterType<Component>();

            container = containerBuilder.Build();
            container.Resolve<Component>().Implement();          
            Console.ReadKey();
        }
    }
}

若想选择指定的构造函数可以用.UsingConstructor方法

namespace ConsoleApp1
{
	class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();

            containerBuilder.RegisterType<ConsoleInput>().As<IInput>();
            containerBuilder.RegisterType<ConsoleOutput>().As<IOutput>();
            containerBuilder.RegisterType<Component>().UsingConstructor(typeof(IOutput));

            container = containerBuilder.Build();
            container.Resolve<Component>().Implement();          
            Console.ReadKey();
        }
    }
}

注意:关于基于反射的组件的一个重要注意事项:通过RegisterType注册的任何组件类型必须是具体类型(比如接口就不行,因为接口不是具体类型)。 虽然组件可以将抽象类或接口公开为服务,但是您不能注册抽象类/接口组件。 如果你想到它是有道理的:在幕后,Autofac正在创建一个你注册的东西的实例。 你不能“新建”一个抽象类或一个接口。

2.实例组件
在某些情况下,您可能希望预先生成对象的实例,并将其添加到容器以供注册组件使用。您可以使用RegisterInstance方法执行此操作。
当你这样做时需要考虑的事情是Autofac自动处理注册组件的清理工作,你可能想要自己控制生命周期,而不是不是让Autofac来帮你调用Dispose 释放你的对象 。在这种情况下,您需要使用ExternallyOwned方法注册该实例。

namespace ConsoleApp1
{
	class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();

            ConsoleOutput output = new ConsoleOutput();
            containerBuilder.RegisterInstance<ConsoleOutput>(output).ExternallyOwned();

            container = containerBuilder.Build();
            using (var scope = container.BeginLifetimeScope())
            {
                scope.Resolve<ConsoleOutput>().Show();
            }

            Console.ReadKey();
        }
    }
}

3.Lambda表达式组件
反射是组件创建的一个相当不错的默认选择。但是,当组件创建逻辑不止是一个简单的构造函数调用时,事情就有些复杂了。Autofac可以接受用作组件创建者的委托或lambda表达式:
在这里插入图片描述
参数c是,组件上下文(一个IComponentContext对象)。您可以使用此来解析容器中的其他值,以帮助创建组件。使用这个参数而不是一个闭包来访问容器非常重要,这样可以保证可以正确地支持确定性清理和嵌套容器。可以使用此上下文参数来满足其他依赖关系 - 在示例中,A需要类型为B的构造函数参数,该参数可能具有其他依赖关系。

using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{   
    public class Student
    {
        private string Name;
        private int Age;
        public Student(string name,int age)
        {
            Name = name;
            Age = age;
        }
        public void Show()
        {
            Console.Write(Name + ":" + Age.ToString());
        }
    }

    class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();

            containerBuilder.Register(o => new Student("Lily", 23));
            container = containerBuilder.Build();

            container.Resolve<Student>().Show();
            Console.ReadKey();
        }
    }
}

应用lambda表达式,通过参数值选择实现

using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{           
    public interface Action
    {
        void Play(string name);
    }

    public class Action1 : Action
    {
        public void Play (string name)
        {
            Console.Write(name + " is listening to the music");
        }
    }

    public class Action2 : Action
    {
        public void Play(string name)
        {
            Console.Write(name + "is dancing");
        }
    }

    class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.Register<Action>((c, o) =>
            {
                string type = o.Named<string>("name");
                if (type == "lily")
                {
                    return new Action1();
                }
                else if (type == "merry")
                {
                    return new Action2();
                }
                else
                {
                    return null;
                }
            });
            
            container = containerBuilder.Build();

            container.Resolve<Action>(new NamedParameter("name", "lily")).Play("lily");
            Console.ReadKey();
        }
    }
}

B) 服务与组件 – 特别留意AsSelf()方法

当您注册组件时,您必须告诉Autofac该组件公开的服务。
默认情况下,大多数注册只会将 自己 公开为已注册的类型,也就是说默认注册调用了AsSelf()方法,且组件只能由其公开的服务解析。
在这里插入图片描述
您可以使用任意数量的 服务 来显示组件,一旦公开服务,您可以基于该服务解析组件。
在这里插入图片描述
但请注意,一旦将组件公开为特定服务,将覆盖默认服务(组件类型)
在这里插入图片描述
如果要将组件公开为一组服务以及使用默认服务,请使用AsSelf方法
在这里插入图片描述
现在所有这些都将工作
在这里插入图片描述

C) 默认注册

如果多个组件公开相同的服务,Autofac将使用最后注册的组件作为该服务的默认提供商:
在这里插入图片描述
在这种情况下,FileLogger将是ILogger的默认值,因为它是最后一个注册的。
要覆盖此行为,请使用PreserveExistingDefaults()修改器,在这种情况下,ConsoleLogger将是ILogger的默认值,因为FileLogger的后续注册使用了PreserveExistingDefaults()。

D) 有条件注册D – OnlyIf(), IfNotRegistered()

OnlyIf() - 提供一个lambda,使用一个IComponentRegistry来确定是否应该发生注册。
IfNotRegistered() - 如果某些其他服务已注册,停止注册的快捷方式。

using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{
    public interface IOutput
    {
        void Show();
    }              
    public interface IInput
    {
        void Get();
    }
    public class Test1 : IOutput
    {
        public void Show()
        {
            Console.Write("Show1");
        }
    }
    public class Test2 : IOutput
    {
        public void Show()
        {
            Console.Write("Show2");
        }
    }
    public class Test3 : IInput
    {
        public void Get()
        {
            Console.Write("GET1");
        }
    }
    class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();            
            containerBuilder.RegisterType<Test1>().As<IOutput>();
            containerBuilder.RegisterType<Test2>().As<IOutput>().IfNotRegistered(typeof(IOutput));
            containerBuilder.RegisterType<Test3>().As<IInput>().OnlyIf(o => o.IsRegistered(new TypedService(typeof(IOutput))));

            container = containerBuilder.Build();
            container.Resolve<IOutput>().Show();
            Console.ReadKey();
        }
    }
}

E) 注册组件带参数

Autofac提供了几种不同的参数匹配策略:

  1. NamedParameter - 按名称匹配目标参数
  2. TypedParameter - 按类型匹配目标参数(需要精确类型匹配)
  3. ResolvedParameter - 灵活的参数匹配
using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{
    public interface IOutput
    {
        void Show();
    } 
    public class Test1 : IOutput
    {
        public string content;
        public Test1(string a)
        {
            content = a;
        }
        public void Show()
        {
            Console.Write(content);
        }
    }

    class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.Register(o => new Test1("HAHA")).As<IOutput>().AsSelf();
            containerBuilder.RegisterType<Test1>().As<IOutput>().AsSelf().WithParameter("a", "yuyu");
            containerBuilder.RegisterType<Test1>().As<IOutput>().AsSelf().WithParameter(new NamedParameter("a", "Haha"));

            container = containerBuilder.Build();
            container.Resolve<IOutput>().Show();
            Console.ReadKey();
        }
    }
}

F) 属性自动关联 – PropertesAutowired()的使用

using Autofac;
using Autofac.Core;
using System;

namespace ConsoleApp1
{
    public interface IInput
    {
        void Get();
    }

    public class ConsoleInput : IInput
    {
        public void Get()
        {
            Console.Write("Input");
        }
    }
    public class Test1 
    {
        public IInput input { get; set; }
        public void Do()
        {
            input?.Get();
        }
    }

    class Program
    {
        private static IContainer container { get; set; }
        static void Main(string[] args)
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.RegisterType<ConsoleInput>().As<IInput>();
            containerBuilder.RegisterType<Test1>().PropertiesAutowired();
            container = containerBuilder.Build();

            container.Resolve<Test1>().Do();
            Console.ReadKey();
        }

		//或
		//static void Main(string[] args)
       	// {
        //    var containerBuilder = new ContainerBuilder();       
        //    containerBuilder.RegisterType<Test1>().WithProperty("input", new ConsoleInput());
        //    container = containerBuilder.Build();

        //   container.Resolve<Test1>().Do();
        //    Console.ReadKey();
        //}	
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值