十年河东,十年河西,莫欺少年穷。
学无止境,精益求精。
新建一个控制台应用程序,如下构造:
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");
}
自此结束
@天才卧龙的博客