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实现。


浙公网安备 33010602011771号