Autofac官方文档翻译--二、解析服务--2隐式关系类型
Autofac 隐式关系类型
1、支持的关系类型
关系 | 类型 | 含义 |
A needs B | B | Direct Dependency(直接依赖关系) |
A needs B at some point in the future | Lazy<B> | Delayed Instantiation(延迟实例化) |
A needs B until some point in the future | Owned<B> | Controlled Lifetime(控制生命周期) |
A needs to create instances of B | Func<B> | Dynamic Instantiation(动态实例) |
A provides parameters of types X and Y to B | Func<X,Y,B> |
Parameterized Instantiation(参数化实例化) |
A needs all the kinds of B |
IEnumerable<B>, IList<B>, ICollection<B> |
Enumeration(枚举) |
A needs to know X about B | Meta<B> and Meta<B,X> | Metadata Interrogation |
A needs to choose B based on X | IIndex<X,B> | Keyed Service Lookup(键控服务查找) |
1.1Direct Dependency (B)--直接依赖
public class A { public A(B dependency) { ... } }
var builder = new ContainerBuilder(); builder.RegisterType<A>(); builder.RegisterType<B>(); var container = builder.Build(); using(var scope = container.BeginLifetimeScope()) { // B 自动注入到 A 中 var a = scope.Resolve<A>(); }
1.2Delayed Instantiation (Lazy<B>)--惰性依赖
public class A { Lazy<B> _b; public A(Lazy<B> b) { _b = b } public void M() { // 在第一次调用 M() 方法时,创建组件 B _b.Value.DoSomething(); } }
1.3 Controlled Lifetime (Owned<B>)
public class A { Owned<B> _b; public A(Owned<B> b) { _b = b; } public void M() { // _b is used for some task _b.Value.DoSomething(); // 这里 _b 不再需要,所以,释放他 _b.Dispose(); } }
在内部,Autofac创建一个微小的lifetime scope,其中对B服务解析,且当你调用它的Dispose()时,这个lifetime scope 将被处理。这也就意味着,释放B也将释放它的依赖关系,除非这些依赖是共享的。
var builder = new ContainerBuilder(); builder.RegisterType<A>().InstancePerLifetimeScope(); builder.RegisterType<B>().InstancePerLifetimeScope(); var container = builder.Build(); using(var scope = container.BeginLifetimeScope()) { // 这里解析一个使用了 InstancePerLifetimeScope() 的 类型 B ; var b1 = scope.Resolve<B>(); b1.DoSomething(); // 这个和上面的 b1 一样。 var b2 = scope.Resolve<B>(); b2.DoSomething(); // 在类型 A 中使用的类型 B 和其他地方的 B 不是同一个 var a = scope.Resolve<A>(); a.M(); }
设计就是这样的,因为你不想让一个组件处理 B 下的一切事情。然而,如果你不知道,它可能会导致一些混乱。
1.4 Dynamic Instantiation (Func<B>)--动态实例化
public class A { Func<B> _b; public A(Func<B> b) { _b = b; } public void M() { var b = _b(); b.DoSomething(); } }
1.5Parameterized Instantiation (Func<X, Y, B>)
public class A { Func<int, string, B> _b; public A(Func<int, string, B> b) { _b = b } public void M() { var b = _b(42, "http://hel.owr.ld"); b.DoSomething(); } }
在内部,Autofac将它们视为类型的参数。这也就意味着,自动生成函数工厂,不能在输入参数列表中有重复的类型。例如,你有这样一个类型:
public class DuplicateTypes { public DuplicateTypes(int a, int b, string c) { // ... } }
var func = scope.Resolve<Func<int, int, string, DuplicateTypes>>(); // Throws a DependencyResolutionException: var obj = func(1, 2, "three");
在一个松耦合的场景下,其中的参数需与类型相匹配,你不了解特定对象的构造函数的参数顺序。如果你需要做这样的事情,你应该使用自定义的委托类型来代替:
public delegate DuplicateTypes FactoryDelegate(int a, int b, string c);
RegisterGeneratedFactory()注册委托
:builder.RegisterType<DuplicateTypes>(); builder.RegisterGeneratedFactory<FactoryDelegate>(new TypedService(typeof(DuplicateTypes)));
现在这个函数将工作:
var func = scope.Resolve<FactoryDelegate>(); var obj = func(1, 2, "three");
你有另一种方式,就是使用使用委托工厂。
var func = container.Resolve<Func<int, string, DuplicateTypes>>(); // This works and is the same as calling // new DuplicateTypes(1, 1, "three") var obj = func(1, "three");
使用这种关系类型且使用委托工厂时推荐使用Lifetime scopes.如果您注册一个对象为InstancePerDependency(),并多次调用Func<X,Y,B>
,每次你将得到一个新实例。但是,如果你注册一个对象为SingleInstance(),并调用Func<X,Y,B>
多次解析对象,你每次都会得到同一个对象实例即使你传递不同的参数。仅仅传递不同的参数不能打破lifetime scope。
1.6 Enumeration (IEnumerable<B>, IList<B>, ICollection<B>)
public interface IMessageHandler { void HandleMessage(Message m); }
此外,你有一个用户的依赖关系,你需要有多个注册和用户需要的所有注册的依赖关系:
public class MessageProcessor { private IEnumerable<IMessageHandler> _handlers; public MessageProcessor(IEnumerable<IMessageHandler> handlers) { this._handlers = handlers; } public void ProcessMessage(Message m) { foreach(var handler in this._handlers) { handler.HandleMessage(m); } } }
您可以使用隐枚举关系类型很容易地做到这一点。只需注册所有的依赖和用户,并且当你解析用户,它所匹配的所有依赖将被解析为一个枚举:
var builder = new ContainerBuilder(); builder.RegisterType<FirstHandler>().As<IMessageHandler>(); builder.RegisterType<SecondHandler>().As<IMessageHandler>(); builder.RegisterType<ThirdHandler>().As<IMessageHandler>(); builder.RegisterType<MessageProcessor>(); var container = builder.Build(); using(var scope = container.BeginLifetimeScope()) { // When processor is resolved, it'll have all of the // registered handlers passed in to the constructor. var processor = scope.Resolve<MessageProcessor>(); processor.ProcessMessage(m); }
如果没有匹配的项目在容器中注册,枚举将返回一个空集。也就是说,使用上面的例子,如果你没有注册任何IMessageHandler 实现时,它将中断:
// This throws an exception - none are registered! scope.Resolve<IMessageHandler>();
// This returns an empty list, NOT an exception: scope.Resolve<IEnumerable<IMessageHandler>>();
你可能认为,如果你使用这种关系注入东西,你会得到一个空值。相反,你会得到一个空列表。
1.7Metadata Interrogation (Meta<B>, Meta<B, X>)
public class A { Meta<B> _b; public A(Meta<B> b) { _b = b; } public void M() { if (_b.Metadata["SomeValue"] == "yes") { _b.Value.DoSomething(); } } }
你也可以使用 strongly-typed 元数据, 通过在 Meta<B,X>
关系中指定元数据类型:
public class A { Meta<B, BMetadata> _b; public A(Meta<B, BMetadata> b) { _b = b; } public void M() { if (_b.Metadata.SomeValue == "yes") { _b.Value.DoSomething(); } } }
如果你有一个惰性依赖也需要元数据,你可以使用Lazy<B,M> 代替Meta<Lazy<B>, M>
1.8 Keyed Service Lookup (IIndex<X, B>)
var builder = new ContainerBuilder(); builder.RegisterType<DerivedB>().Keyed<B>("first"); builder.RegisterType<AnotherDerivedB>().Keyed<B>("second"); builder.RegisterType<A>(); var container = builder.Build();
然后使用IIndex<X,B>得到一个keyd服务字典:
public class A { IIndex<string, B> _b; public A(IIndex<string, B> b) { _b = b; } public void M() { var b = this._b["first"]; b.DoSomething(); } }
2、组成关系类型
IEnumerable<Func<Owned<ITask>>>
正确的解释为:
- All implementations, of
- Factories, that return
- Lifetime-controlled
- ITask services
3、关系类型和容器独立
Func<Owned<ITask>>
的AutofacTaskFactory实现。