C# Autofac 构造函数注入,属性注入,方法注入

十年河东,十年河西,莫欺少年穷。

学无止境,精益求精。

新建一个控制台应用程序,如下构造:

 MyAutoFac层引入autofac 版本 V6.5

接口层如下:

namespace MyInterface
{
    public interface IPerson
    {
        void say();
        void PlayerWithDog();
        void PlayerWithCat();
        void PlayerWithPig();
    }
    public interface IDog
    {
        void say();
    }

    public interface ICat
    {
        void say();
    }
    public interface IPig
    {
        void say();
    } 
}

服务层如下:

namespace MyService
{
    public class PersonService : IPerson
    {
        private readonly IDog dog;
        private readonly ICat cat;
        private readonly IPig pig;
        public PersonService(IDog dog)
        {
            this.dog = dog;
        }
        public PersonService(IDog dog, ICat cat)
        {
            this.dog = dog;
            this.cat = cat;
        }
        public PersonService(IDog dog,  IPig pig, ICat cat)
        {
            this.pig = pig;
            this.cat = cat;
        }
        public void say()
        {
            Console.WriteLine("你好");
        }

        public void PlayerWithDog()
        {
            if (dog == null)
            {
                return;
            }
            Console.WriteLine("人在跳绳,狗在叫:");
            this.dog.say();
        }

        public void PlayerWithCat()
        {
            if (cat == null)
            {
                return;
            }
            Console.WriteLine("人在跳绳,猫在叫:");
            this.cat.say();
        }
        public void PlayerWithPig()
        {
            if (pig == null)
            {
                return;
            }
            Console.WriteLine("人在跳绳,猪在叫:");
            this.pig.say();
        }
    }

    public class DogService : IDog
    {
        public void say()
        {
            Console.WriteLine("汪汪汪");
        }
    }

    public class CatService : ICat
    {
        public void say()
        {
            Console.WriteLine("喵喵喵");
        }
    }

    public class PigService : IPig
    {
        public void say()
        {
            Console.WriteLine("哼哼哼");
        }
    }
}

1、构造函数注入

1.1、构造函数默认注入

引入一个构造函数参数

{
    //构造函数默认注入
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IDog>();
    builder.RegisterType<PersonService>().As<IPerson>();
    IContainer container = builder.Build();
    var p = container.Resolve<IPerson>();
    p.say();
    p.PlayerWithDog();
}

上述代码中先通过RegisterType引入IDog,后引入IPerson,会执行PersionService中有一个IDog作为参数的构造函数

调式如下:


 

将上述代码修改如下:

引入三个构造函数参数

{
    //构造函数默认注入
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IDog>();
    builder.RegisterType<PigService>().As<IPig>();
    builder.RegisterType<CatService>().As<ICat>();
    builder.RegisterType<PersonService>().As<IPerson>();
    IContainer container = builder.Build();
    var p = container.Resolve<IPerson>();
    p.say();
    p.PlayerWithDog();
}

通过RegisterType引入了IDog、ICat、IPig,因此会走具有三个参数的构造函数

调试如下:


 

将代码继续修改如下:

 通过反射,加载所有接口及其实现类

{
    //通过程序集加载
    ContainerBuilder builder = new ContainerBuilder();
    Assembly assemblyInterface = Assembly.LoadFrom("MyInterface.dll");
    Assembly assemblyService = Assembly.LoadFrom("MyService.dll");
    builder.RegisterAssemblyTypes(assemblyInterface, assemblyService).AsImplementedInterfaces();
    IContainer container = builder.Build();
    //PersonService 会执行参数多的构造函数
    var p = container.Resolve<IPerson>();
    p.PlayerWithDog(); p.PlayerWithCat(); p.PlayerWithPig();
}

调式如下:

这里需要说明的是,如果构造函数中有相同参数个数的构造函数,AutoFac会报错,他就不知道该执行哪个构造函数了。

 1.2、通过UsingConstructor方法指定要执行的构造函数

代码如下:

{
    //注册一个普通类
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IDog>();
    builder.RegisterType<CatService>().As<ICat>();
    builder.RegisterType<PersonService>().As<IPerson>().UsingConstructor(typeof(IDog), typeof(ICat));
    IContainer container = builder.Build();
    var p = container.Resolve<IPerson>();
    p.say();
    p.PlayerWithDog();
    p.PlayerWithCat();
}

 调式如下

 2、属性注入

2.1、PropertiesAutowired()方法属性注入

使用PropertiesAutowired()方法支持属性注入

新增接口及实现类如下:

接口

    /// <summary>
    /// 动物接口
    /// </summary>
    public interface IAnimal
    {
        void say();
    }

实现类【实现类中有三个属性】

    public class AnimalService : IAnimal
    {

        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        /// 
        public IDog dog { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        /// 
        public ICat cat { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        public IPig pig { get; set; }

        public void say()
        {
            if (this.dog != null)
            {
                this.dog.say();
            }
            if (this.cat != null)
            {
                this.cat.say();
            }
            if (this.pig != null)
            {
                this.pig.say();
            }
        }
    }

 

代码如下

{
    //属性注入
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IDog>();
    builder.RegisterType<CatService>().As<ICat>();
    builder.RegisterType<PigService>().As<IPig>();
    builder.RegisterType<AnimalService>().As<IAnimal>().PropertiesAutowired();
    IContainer container = builder.Build();
    var p = container.Resolve<IAnimal>();
    p.say();
}

 调式如下:

 2.2、属性注入选择器

新建属性类及属性选择器如下:

namespace MyIocAutoProperties
{
    [AttributeUsage(AttributeTargets.Property)]
    public class IocSelectAttribute: Attribute
    {

    }

    public class IoctAttributeSelector : IPropertySelector
    {
        public bool InjectProperty(PropertyInfo propertyInfo, object instance)
        {
            return propertyInfo.CustomAttributes.Any(A => A.AttributeType == typeof(IocSelectAttribute));
        }
    }
}

修改如下:

    public class AnimalService : IAnimal
    { 
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        /// 
        [IocSelect]
        public IDog dog { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        /// 
        [IocSelect]
        public ICat cat { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        public IPig pig { get; set; }

        public void say()
        {
            if (this.dog != null)
            {
                this.dog.say();
            }
            if (this.cat != null)
            {
                this.cat.say();
            }
            if (this.pig != null)
            {
                this.pig.say();
            }
        }
    }
View Code

 

 代码如下:

{
    //属性注入
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IDog>();
    builder.RegisterType<CatService>().As<ICat>();
    builder.RegisterType<PigService>().As<IPig>();
    builder.RegisterType<AnimalService>().As<IAnimal>().PropertiesAutowired(new IoctAttributeSelector());
    IContainer container = builder.Build();
    var p = container.Resolve<IAnimal>();
    p.say();
}
View Code

 

 吊事如下:

 3、方法注入

所谓方法注入是指:在接口对象构造后,自动调用对象的某个方法

在接口中增加一个Eat方法

    /// <summary>
    /// 动物接口
    /// </summary>
    public interface IAnimal
    {
        void say();
        void eat(ICat cat);
    }

实现类如下:

    public class AnimalService : IAnimal
    { 
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        ///  
        public IDog dog { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        ///  
        public ICat cat { get; set; }
        /// <summary>
        /// 属性注入时,修饰符必须为Public
        /// </summary>
        public IPig pig { get; set; }

        public void say()
        {
            if (this.dog != null)
            {
                this.dog.say();
            }
            if (this.cat != null)
            {
                this.cat.say();
            }
            if (this.pig != null)
            {
                this.pig.say();
            }
        }

        public void  eat(ICat cat)
        {
            Console.WriteLine("方法注入:在构建IAnimal对象时,触发eat方法执行");
        }
    }
View Code

代码如下:

{
    //方法注入
    ContainerBuilder builder = new ContainerBuilder(); 
    builder.RegisterType<CatService>().As<ICat>();
    builder.RegisterType<AnimalService>().As<IAnimal>().OnActivated(Activator =>
    {
        var cat = Activator.Context.Resolve<ICat>();
        Activator.Instance.eat(cat);
    }); 
    IContainer container = builder.Build();
    //构建IAnimal对象,触发上述eat方法执行
    container.Resolve<IAnimal>();
}

程序将在 container.Resolve<IAnimal>(); 之后,执行eat方法

调式如下:

 

 4、单抽象,多实现

如下案例

    /// <summary>
    /// 动物接口
    /// </summary>
    public interface IAnimal
    {
        void say(); 
    }

多个实现类继承该接口

    public class DogService : IAnimal
    {
        public void say()
        {
            Console.WriteLine("汪汪汪");
        }
    }

    public class CatService : IAnimal
    {
        public void say()
        {
            Console.WriteLine("喵喵喵");
        }
    }

    public class PigService : IAnimal
    {
        public void say()
        {
            Console.WriteLine("哼哼哼");
        }
    }
View Code

先看如下代码:

{
    //单抽象多继承
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().As<IAnimal>();
    builder.RegisterType<CatService>().As<IAnimal>();
    builder.RegisterType<PigService>().As<IAnimal>();
    IContainer container = builder.Build(); 
    var p = container.Resolve<IAnimal>();
    var ps = container.Resolve<IEnumerable<IAnimal>>(); 
}

p为最后注册的对象

 

 ps为所有实现类对象集合

 

 那么问题来了,我们该如何获取到指定的对象呢?

通过加入key来识别即可,如下

{
    //单抽象多继承
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterType<DogService>().Keyed<IAnimal>("dog");
    builder.RegisterType<CatService>().Keyed<IAnimal>("cat");
    builder.RegisterType<PigService>().Keyed<IAnimal>("pig");
    IContainer container = builder.Build();
    //这里是狗
    var dog = container.ResolveKeyed<IAnimal>("dog");
    //这里是猫
    var cat = container.ResolveKeyed<IAnimal>("cat");
    //这里是猪
    var pig = container.ResolveKeyed<IAnimal>("pig"); 
}

自此结束

@天才卧龙的博客

posted @ 2023-02-08 15:49  天才卧龙  阅读(1854)  评论(0编辑  收藏  举报