autoFac——茴字的三种写法

autofac版本:3.5.2

创建容器

var builder = new ContainerBuilder();

注册方式(这一部分的关注点在于给RegisterType、RegisterAssemblyTypes方法传递的参数,以及可以使用lambda表达式进行筛选

  1、泛型/类型注册,好处是很方便,但是缺点是:所注册的类型需要在当前项目中引用。使用了泛型注册,必须要类型明确。

builder.RegisterType<MSDService>().As<IService>();

  2、使用反射+类名字符串进行注册。使用这种注册方式进行注册的类,是可以不需要进行引用的,但是类所在的程序集需要事先被加载进来。(动态加载的时候可以使用这种方式)

builder.RegisterType(System.Type.GetType("MvcApplication1.Services.MSDService"));

  3、批量注册指定程序集中的所有非静态类。

builder.RegisterAssemblyTypes(Assembly.Load("MSD.BLL"));

    3.1、通常我们并不需要注册一个程序集中所有的类。所以可以使用lambda表达式进行过滤。

         Assembly assembly = Assembly.GetExecutingAssembly();
         builder.RegisterAssemblyTypes(assembly).Where(x => x.Namespace.Equals("MvcApplication1.Services"));//注册指定命名空间下的所有类型。
         builder.RegisterAssemblyTypes(assembly).InNamespaceOf<MSDService>();//注册MSDService类型所在的命名空间下的所有类型。
         builder.RegisterAssemblyTypes(assembly).Except<MSDService>();//不注册MSDService类。
         builder.RegisterAssemblyTypes(assembly).InNamespace("MvcApplication1.Services");//注册在指定命名空间下的所有类。

  4、Lambda注册。1~3所使用的注册方式都是通过构造函数直接new出了对象。如果想在注册之时为类做更多的事情可以通过lambda表达式的注册方式进行注册。

builder.Register(iComponentContext =>
            {
                MSDService af = new MSDService();
                if (af.Guid == null)
                    af.Guid = new System.Guid();//例子举的不好,但是大致的意思就是可以在注册之时,做其他的事情。
                return af;
            });

  5、模块注册(这种注册方式最方便,在多人同时协作一个项目的时候,如果使用上面的方式,难免会产生代码冲突,使用这种就可以避免这种情况,只要各自实现IModule接口就可以了)。

builder.RegisterAssemblyModules(assembly);//1、Module实现了IModule接口。2、RegisterAssemblyModules所注册的是实现了IModule接口的类。
builder.RegisterAssemblyModules<MSDService>(assembly);//只注册assembly程序集中继承自MSDService的模块。

解析已注册的类型

IContainer container = builder.Build();
IService msdService = container.Resolve<MSDService>();//如果事先没有对MSDService进行注册,那么Resolve时将会抛出异常。
IService msdService1 = container.ResolveOptional<MSDService>();//如果事先没有对MSDService进行注册,那么将返回一个null值。
IService msdService2 = null;
if (container.TryResolve(out msdService2))//类似于tryParse
{
   //如果解析成功
}
else
{
  //如果解析失败
}

当一个类有多个构造函数的情况下,autofac会使用哪一个构造函数?

使用尽可能最多参数的那个构造函数。详情:https://www.cnblogs.com/ancupofcoffee/p/5008469.html

可以通过传入指定参数,从而来指定使用哪一种构造函数来生成我们需要的类型。

var obj = container.Resolve<People>(new NamedParameter("guid", Guid.NewGuid()));

NamedParameter     根据参数名称进行匹配。
PositionalParameter      根据参数索引进行匹配,注意:起始索引为0。
TypedParameter      根据类型进行匹配,注意:传入多个相同类型的TypedParameter,所有该类型的参数都将采用第一个TypedParameter的值。
ResolvedParameter   接收两个Func参数,两个Func签名都接收两个相同的参数ParameterInfo和IComponmentContext,第一个参数为参数的信息,第二个参数还是当做IContainer使用就好了。第一个Func的返回值为bool,表明当前这个ResolvedParameter是否使用当前匹配到的参数,如果返回true,则会执行第二个Func;第二个Func返回一个object对象,用于填充构造参数值。

            container.Resolve<People>(new ResolvedParameter(
             x =>
             {

             },
             y =>
             {

             }
            ));

注入方式(这部分要关注点是:结合Person和Eating的构造函数或属性,使用不同的方法进行注册,以及在注册时,可能会碰到的问题)

    public class Person
    {
        public Eating eat = null;


        //public Person(Eating eat)//如果加上这个构造函数,那么就是属性注入。去掉了,就是自动属性注入
        //{
        //    this.eat = eat;
        //}

        public string Name { get; set; }


        public void Eating()
        {
            eat.DoSth();
        }
    }
Person.cs
    public class Eating
    {
        public void DoSth() {

        }
    }
Eating.cs

1、属性注入

builder.RegisterType<Models.Eating>();
builder.RegisterType<Models.Person>();
var container1 = builder.Build();
var person = container1.Resolve<Models.Person>();//在person类的构造函数里传入了Eating,但是并不需做其他的操作,只要在之此之前注册Eating就可以了。

2、自动属性注入

builder.RegisterType<Models.Eating>();
builder.RegisterType<Models.Person>().PropertiesAutowired();//使用了PropertiesAutowired方法,只有在autofac中注册过的类型, 才能注入进去。
var container2 = builder.Build();
var person1 = container1.Resolve<Models.Person>();

3、指定属性注入

builder.RegisterType<Models.Person>().WithProperty(new Autofac.Core.NamedPropertyParameter("eat", new Models.Eating()));
builder.RegisterType<Models.Person>().WithProperty("eat", new Models.Eating());

4、lambda表达式注入

builder.Register(iComponentContext =>
            {
                Models.Person p = new Models.Person();
                p.eat = new Models.Eating();//人为地注入了一个Eating
                return p;
            });

推荐使用不需要传参的构造注入和自动属性注入。不推荐使用方法注册。如果关联类型与注册类型没有继承/实现,那么builder.Build()会报错。

5、当一个类与多个接口进行关联时

builder.RegisterType<C1>().As<I1>().As<I2>().AsSelf();//不使用AsSelf(),如果想获取到一个I3接口的对象,就会抛异常。(只能获取到I1和I2)
builder.RegisterType<C1>().AsImplementedInterfaces();
一个接口或类型只能与一个类型进行关联,后面的关联会覆盖前面的关联。
builder.RegisterType<C1>().As<I1>(); // class C1 : I1
builder.RegisterType<C2>().As<I1>(); // class C2 : I1
如果不想让后面的关联覆盖前面的关联,可以像下面这样做
builder.RegisterType<C2>().As<I1>()PreserveExistingDefaults()//这样,C2就不会和I1进行关联了。

可以使用Named <>、Meta<>方法,让一个接口和多个类型进行关联。

最后,autoFac有5个生命周期函数(感觉跟vue或小程序中的差不多)

  1、OnRegistered

  2、OnPreparing

  3、OnActivating:OnActivating事件中推荐的三种操作:1.替换实例对象,或使用代理对象(通过ReplaceInstance方法);2.执行属性注入或方法注入;3.执行其他初始化任务。

  4、OnActived:OnActived事件中可以执行一些应用程序级别的任务。

  5、OnRelease

builder.RegisterType<A>().OnActivating(e=>{调用一个方法去注册});
var builder = new ContainerBuilder();
builder.RegisterCallback(cr =>
            {
                // 下面的Registered事件相当类型的OnRegistered事件
                cr.Registered += (sender, eventArgs) =>
                {
                    // OnPreparing事件
                    eventArgs.ComponentRegistration.Preparing += (o, preparingEventArgs) =>
                    {

                    };
                    // OnActivating事件
                    eventArgs.ComponentRegistration.Activating += (o, activatingEventArgs) =>
                    {

                    };
                    // OnActivated事件
                    eventArgs.ComponentRegistration.Activated += (o, activatedEventArgs) =>
                    {

                    };
                };
            });
// builder.RegisterType<...>...继续写其他的注册代码
统一事件注册

原文地址:https://www.cnblogs.com/ancupofcoffee/category/761892.html

猜你喜欢

转载自www.cnblogs.com/vichin/p/13174546.html