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(); } } }
代码如下:

{ //属性注入 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(); }
吊事如下:
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方法执行"); } }
代码如下:
{ //方法注入 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("哼哼哼"); } }
先看如下代码:
{ //单抽象多继承 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"); }
自此结束
@天才卧龙的博客
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!