1. 术语
1.1 解析根(Resolution Root)
解析根是通过调用Resolve
方法从容器中获取到的一个服务
对象。以下代码中的client
就是一个解析根。
var client = container.Resolve<IClient>();
1.2 注入的依赖(Injected Dependency)
void Main()
{
var container = new Container();
container.Register<IClient, SomeClient>();
container.Register<IService, SomeService>();
var client2 = container.Resolve<IClient>();
}
public interface IService { }
public class SomeService : IService{}
public interface IClient{ IService Service { get; }}
public class SomeClient : IClient
{
public IService Service { get; }
public SomeClient(IService service){}
}
上面的例子中,SomeClient
的构造函数中有个IService
类型的参数。该参数是在调用container.Resolve<IClient>()
时通过容器自动注入的,这个参数就称为类型SomeClient
的注入的依赖。DryIOC
支持以下类型的注入:
- 构造注入
首选
- 属性/字段注入
不推荐
1.3 实现类型(Implementation Type)
实现类型通常为一个接口或抽象类型的具体实现类型。
在1.2
的例子中SomeClient
与SomeService
就是实现类型。此外,DryIOC
支持开放式泛型的实现类型:OtherService<>
。
1.4 服务类型(Service Type)
服务类型通常为一个接口或抽象类型。此外,可以使用实现类型作为服务类型。DryIOC
亦支持开放式服务类型:IService<>
。
2. 注册API
DryIOC
使用Register...
方法进行注册。
2.1 常规注册
var container = new Container();
container.Register<IClient, SomeClient>();
container.Register<IService, SomeService>();
2.2 类型参数注册
如果在编译时不知道具体的类型,可以使用以下方式进行注册:
var container = new Container();
container.Register(typeof(IClient), typeof(SomeClient));
container.Register(typeof(IService), typeof(SomeService));
2.3 开放式泛型注册
void Main()
{
var container = new Container();
container.Register(typeof(IService<>), typeof(SomeService<>));
var s = container.Resolve<IService<string>>();
}
interface IService<T> { }
class SomeService<T> : IService<T> { }
2.4 实现类型作为服务类型
var container = new Container();
// 以下两种方式等价
container.Register<SomeService>();
container.Register(typeof(SomeService));
2.5 底层的注册API
上述所使用的API都是通过对通过一个底层注册API的高层封装,这个底层API定义在 IRegistrator
接口中。
void Register(Factory factory,
Type serviceType,
object serviceKey,
IfAlreadyRegistered? ifAlreadyRegistered,
bool isStaticallyChecked);
DryIoc
中的工厂是一个实体,它保存创建服务所需的所有信息和行为。Factory
是一个抽象类,DryIOC
中实现的工厂如下:
ReflectionFactory
DelegateFactory
ExpressionFactory
void Main()
{
var container = new Container();
container.Register(typeof(IA), new ReflectionFactory(typeof(A), Reuse.Singleton));
var a = container.Resolve<IA>();
}
interface IA { }
class A : IA { }
3. 单例注册
将一个服务类型注册为单例模式后,无论是通过解析或注册该服务类型所对应的实现类型,都将得到相同的实例。
var container = new Container();
container.Register<IClient, SomeClient>();
container.Register<IService, SomeService>(Reuse.Singleton); // 单例注册
// 获取两个实例,但是这两个实例都的注入依赖是单例的,因此注入的依赖是同一个实例
var one = container.Resolve<IClient>();
var two = container.Resolve<IClient>();
Console.WriteLine(two.Service == one.Service); // True
4. 注册多个实现
分为两种情况,一是默认注册,一是关键字注册。
4.1 默认注册
不能通过获取直接的实现类型,而需要获取所有对应服务类型的实现类型的集合。
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>();
container.Register<ICommand, SetCommand>();
container.Register<ICommand, DeleteCommand>();
// 直接解析服务会发生异常,因为通过一个服务类型注册了多个实现类型。容器不清楚该创建哪一个实现类型的实例
// container.Resolve<ICommand>();
// 可通过以下两种方式进行获取所有注册的实现类型的集合
// 方式一
// 支持数组或数组所实现的接口
Console.WriteLine(container.Resolve<IEnumerable<ICommand>>().Count()); // 3
Console.WriteLine(container.Resolve<ICommand[]>().Count());
Console.WriteLine(container.Resolve<IList<ICommand>>().Count());
Console.WriteLine(container.Resolve<ICollection<ICommand>>().Count());
Console.WriteLine(container.Resolve<IReadOnlyList<ICommand>>().Count());
Console.WriteLine(container.Resolve<IReadOnlyCollection<ICommand>>().Count());
// 方式二
Console.WriteLine(container.ResolveMany<ICommand>().Count()); // 3
}
internal interface ICommand { }
internal class GetCommand : ICommand { }
internal class SetCommand : ICommand { }
internal class DeleteCommand : ICommand { }
使用默认方式注册多个实现类型,
DryIOC
内部使用一个类型为DefaultKey
的特殊键值进行区分
解析获取的实现类型集合中实现类型的顺序与注册时的顺序相同
可以通过以下方式选择某个实现类型,以避免调用Resolve<ICommand>
时发生异常。
- 注册时使用条件参数
使用这种方式,虽然为一个服务类型注册了多个实现类型,但是仅能获取其中一种实现类型的实例
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>(setup: Setup.With(condition: req => req.IsResolutionRoot));
container.Register<ICommand, SetCommand>(setup: Setup.With(condition: req => !req.IsResolutionRoot));
container.Register<ICommand, DelCommand>(setup: Setup.With(condition: req => !req.IsResolutionRoot));
Console.WriteLine(container.Resolve<ICommand>() is GetCommand); // True
}
internal interface ICommand { }
internal class GetCommand : ICommand { }
internal class SetCommand : ICommand { }
internal class DelCommand : ICommand { }
- 指定元数据类型
通过元数据进行结果筛选,每次都是获取一个集合,效率上有所降低。
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Get));
container.Register<ICommand, SetCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Set));
container.Register<ICommand, DelCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Del));
container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().Dump();
Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Get).Value is GetCommand); // True
Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Set).Value is SetCommand); // True
Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Del).Value is DelCommand); // True
}
interface ICommand {}
class GetCommand : ICommand {}
class SetCommand : ICommand {}
class DelCommand : ICommand {}
enum CommandId { Get, Set, Del }
- 使用重用方式边界来指定父作用域,或命名作用域
当指定的作用域被释放时,该作用域所存储的实现类型亦被释放。
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>(reuse:Reuse.ScopedTo("Get"));
container.Register<ICommand, SetCommand>(reuse:Reuse.ScopedTo("Set"));
container.Register<ICommand, DelCommand>(reuse:Reuse.ScopedTo("Del"));
using(var getScope = container.OpenScope(name:"Get"))
{
Console.WriteLine(getScope.Resolve<ICommand>() is GetCommand); // True
}
using (var setScope = container.OpenScope(name: "Set"))
{
Console.WriteLine(setScope.Resolve<ICommand>() is SetCommand); // True
}
using (var delScope = container.OpenScope(name: "Del"))
{
Console.WriteLine(delScope.Resolve<ICommand>() is DelCommand); // True
}
}
- 使用关键字注册
下一章节进行说明
4.2 关键字注册
在注册时提供一个服务关键字
。该关键字是任意实现了Object.GetHashCode
和Object.Equals
的类型。通常使用enum
, string
,number
。
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>(serviceKey: CommandId.Get);
container.Register<ICommand, SetCommand>(serviceKey: CommandId.Set);
container.Register<ICommand, DelCommand>(serviceKey: CommandId.Del);
Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Get) is GetCommand); // True
Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Set) is SetCommand); // True
Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Del) is DelCommand); // True
}
interface ICommand { }
class GetCommand : ICommand { }
class SetCommand : ICommand { }
class DelCommand : ICommand { }
enum CommandId { Get, Set, Del }
与Lazy
或Func
结合使用。
void Main()
{
var container = new Container();
container.Register<ICommand, GetCommand>(serviceKey: CommandId.Get);
container.Register<ICommand, SetCommand>(serviceKey: CommandId.Set);
container.Register<ICommand, DelCommand>(serviceKey: CommandId.Del);
var commands = container.Resolve<KeyValuePair<CommandId, ICommand>[]>();
commands.Dump(nameof(commands));
var lazyCommands = container.Resolve<KeyValuePair<CommandId, Lazy<ICommand>>[]>();
lazyCommands.Dump(nameof(lazyCommands));
var commandFactories = container.Resolve<KeyValuePair<CommandId, Func<ICommand>>[]>();
commandFactories.Dump(nameof(commandFactories));
}
interface ICommand { }
class GetCommand : ICommand { }
class SetCommand : ICommand { }
class DelCommand : ICommand { }
enum CommandId { Get, Set, Del }
4.3 KeyValuePair 封装
DryIOC
支持将已注册的服务解析为对应的服务关键字的键值对KeyValuePair<KeyType, ServiceType>
。这种模式能够工作于默认模式和关键字模式,因为默认模式下内部使用类型为DefaultKey
的键。
当解析一个服务集合时,如果集合中的服务类型的键值的类型不同,需要使用
object
作为KeyType
的类型。
void Main()
{
var container = new Container();
container.Register<I, X>();
container.Register<I, Y>();
container.Register<I, Z>(serviceKey: "z");
// 使用object类型作为键的类型,获取所有实现类型
var allItems = container.Resolve<KeyValuePair<object, I>[]>();
allItems.Dump(nameof(allItems));
// 获取默认键值的实现对象集合
var defaultItems = container.Resolve<KeyValuePair<DefaultKey, I>[]>();
defaultItems.Dump(nameof(defaultItems));
// 获取指定键值类型的实现对象集合
var stringItems = container.Resolve<KeyValuePair<string, I>[]>();
stringItems.Dump(nameof(stringItems));
}
interface I { }
class X : I { }
class Y : I { }
class Z : I { }
注意
DryIOC
不保证非默认关键字注册的实现类型在解析树的集合中出现的顺序。例如,上例中z
关键字在最后注册,但可能出现在集合中非最后的位置。
5. 判断一个服务是否已经被注册
5.1 检查服务是否注册
DryIOC
使用IsRegistered
方法测试一个服务、装饰器或封装器是否被注入到容器。此外,IsRegistered
允许提供一个条件参数来测试服务的工厂实现,即能够测试一份注册服务的相关信息。
void Main()
{
var c = new Container();
// 未注册时
Console.WriteLine(c.IsRegistered<MyService>()); // False
Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // False
c.Register<MyService>();
// 注册但非单例
Console.WriteLine(c.IsRegistered<MyService>()); // True
Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // False
c.Register<MyService>(Reuse.Singleton);
// 注册单例
Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // True
// 对一个服务注册不同的重用类型,将使用最后一个注册
Console.WriteLine(c.Resolve<MyService>() == c.Resolve<MyService>()); // True
}
class MyService { }
5.2 检查是否注册默认键类型或关键字类型
默认情况下,IsRegistered
检查所有类型的注册。如果期望仅对默认注册或关键字注册进行检查,请看如下例程。
void Main()
{
var c = new Container();
// 关键字注册
c.Register<MyService>(serviceKey: "the key");
// 检查一个服务是否通过指定关键字进行注册
Console.WriteLine(c.IsRegistered<MyService>(serviceKey: "the key")); // True
// 检查是否存在默认键注册的类型
Console.WriteLine(c.IsRegistered<MyService>(serviceKey: DefaultKey.Value)); // False
// 如果没有服务关键字,将检查所有类型的注册
Console.WriteLine(c.IsRegistered<MyService>()); // True
// 默认注册
c.Register<MyService>();
// 检查是否存在默认键注册的类型
Console.WriteLine(c.IsRegistered<MyService>(serviceKey: DefaultKey.Value)); // True
}
class MyService { }
5.3 检查装饰器或封装其是否被注册
默认情况,IsRegistered
仅检查服务是否被注册,而不去检测装饰器
或封装器
。如果要实现装饰器
或封装器
是否注册的检查功能,需要指定对应的FactoryType
。
void Main()
{
var c = new Container();
Console.WriteLine(c.IsRegistered(typeof(Owned<>), factoryType: FactoryType.Wrapper)); // False
c.Register(typeof(Owned<>), setup: Setup.Wrapper);
Console.WriteLine(c.IsRegistered(typeof(Owned<>), factoryType: FactoryType.Wrapper)); // True
}
class Owned<T> { }
IsRegistered
不检查一个实现类型是否可以被成功解析
5.4 检查一个类型是否可解析
如果一个类型被注册,但是其依赖未被注册,通过IfUnresolved.ReturnDefault
检查其可解析性。
void Main()
{
var c = new Container();
Console.WriteLine(c.Resolve<MyService>(ifUnresolved: IfUnresolved.ReturnDefault) != null);
c.Register<MyService>();
Console.WriteLine(c.Resolve<MyService>(ifUnresolved: IfUnresolved.ReturnDefault) != null);
// 如果仅仅是判断解析性而不需要创建实例,使用Func进行封装
Console.WriteLine(c.Resolve<Func<MyService>>(ifUnresolved: IfUnresolved.ReturnDefault) != null);
}
class MyService { }
5.5 显示地检查一个服务是否被注册
基本思想是获取容器内的所有注册,然后根据指定条件进行筛选。
void Main()
{
var c = new Container();
c.Register<MyService>(Reuse.Scoped, serviceKey: "foo");
var serviceRegistration = c.GetServiceRegistrations().FirstOrDefault(r => Equals(r.OptionalServiceKey, "foo") && r.Factory.Reuse == Reuse.Scoped);
Console.WriteLine(typeof(MyService) == serviceRegistration.ImplementationType); // True
}
class MyService { }
6. RegisterMany
有时一个实现类型实现了多个服务类型,这时的注册可以分成多种情况。
6.1 使用实现类型,同时注册本身及其实现接口``
void Main()
{
var container = new Container();
// 使用实现类型A,同时注册本身及其实现接口
container.RegisterMany<A>();
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // True
Console.WriteLine(container.IsRegistered(typeof(A))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
6.2 使用实现类型,仅注册其实现接口
void Main()
{
var container = new Container();
container.RegisterMany<A>(serviceTypeCondition: type => type.IsInterface);
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // True
Console.WriteLine(container.IsRegistered(typeof(A))); // False
}
public interface X { }
public interface Y { }
public class A : X, Y { }
6.3 接口与实现共享实例
void Main()
{
var container = new Container();
container.RegisterMany<A>(Reuse.Singleton);
Console.WriteLine(container.Resolve<X>() == container.Resolve<Y>()); // True
Console.WriteLine(container.Resolve<X>() == container.Resolve<A>()); // True
Console.WriteLine(container.Resolve<Y>() == container.Resolve<A>()); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
6.4 用接口X与Y注册A,接口X注册B
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(new[] { typeof(A), typeof(B) }, serviceTypeCondition: type => type.IsInterface);
// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
container.Resolve<X[]>().Dump("X");
container.Resolve<Y>().Dump("Y");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
public void Dispose() { }
}
6.5 用X接口注册A与B
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(new[] { typeof(A), typeof(B) }, serviceTypeCondition: type => type == typeof(X));
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // False
Console.WriteLine(container.IsRegistered(typeof(A))); // False
Console.WriteLine(container.IsRegistered(typeof(B))); // False
// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
container.Resolve<X[]>().Dump("X");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
public void Dispose() { }
}
6.6 如果A与B在同一个程序集中
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(new[] { typeof(A).Assembly }, type => type == typeof(X));
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // False
Console.WriteLine(container.IsRegistered(typeof(A))); // False
Console.WriteLine(container.IsRegistered(typeof(B))); // False
// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
container.Resolve<X[]>().Dump("X");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
public void Dispose() { }
}
6.7 使用Made.Of表达式
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(Made.Of(() => CreateA()));
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // True
Console.WriteLine(container.IsRegistered(typeof(A))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public static A CreateA() => new A();
6.8 显示类型注册
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(new[] { typeof(X), typeof(Y) }, typeof(A));
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // True
Console.WriteLine(container.IsRegistered(typeof(A))); // False
}
public interface X { }
public interface Y { }
public class A : X, Y { }
6.9 通用注册
DryIOC
排除某些类型作为RegisterMany
函数的服务类型。这些类型包括基元类型、object、string、IDisposable、ICloneable接口等。此外,编译器生成的类型也被排除在外。
void Main()
{
var container = new Container(rules => rules.WithTrackingDisposableTransients());
container.RegisterMany(
implTypeAssemblies: new[] { typeof(A).Assembly },
getServiceTypes: implType => implType.GetImplementedServiceTypes(),
getImplFactory: implType => new ReflectionFactory(implType, reuse: implType.IsAssignableTo<IDisposable>() ? Reuse.Scoped : Reuse.Transient, made: FactoryMethod.ConstructorWithResolvableArguments));
Console.WriteLine(container.IsRegistered(typeof(X))); // True
Console.WriteLine(container.IsRegistered(typeof(Y))); // True
Console.WriteLine(container.IsRegistered(typeof(A))); // True
Console.WriteLine(container.IsRegistered(typeof(B))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public static A CreateA() => new A();
public class B : X, IDisposable
{
public void Dispose() { }
}
7. RegisterMapping
该功能可以将一个新服务类型注册到已有的已注册的服务及其实现。
void Main()
{
var container = new Container();
container.Register<I, S>(Reuse.Singleton);
container.RegisterMapping<J, I>();
Console.WriteLine(container.IsRegistered(typeof(I))); // True
Console.WriteLine(container.IsRegistered(typeof(J))); // True
Console.WriteLine(container.Resolve<I>() == container.Resolve<J>()); // True
}
public interface I { }
public interface J { }
class S : I, J { }
8. RegisterDelegate
可以通过注册自定义的委托作为服务工厂。
void Main()
{
var container = new Container();
container.RegisterDelegate<IService>(resolverContext => new CheerfulService { Greetings = "Hey!" });
var x = container.Resolve<IService>();
Console.WriteLine(((CheerfulService)x).Greetings);
}
interface IService{ }
class CheerfulService : IService
{
public string Greetings { get; set; }
}
void Main()
{
var container = new Container();
container.RegisterDelegate(_ => new GreetingsProvider { Greetings = "Mya" });
container.RegisterDelegate<IService>(resolverContext => new CheerfulService(resolverContext.Resolve<GreetingsProvider>()));
var x = container.Resolve<IService>();
Console.WriteLine(((CheerfulService)x).Greetings);
}
interface IService { }
class CheerfulService : IService
{
public string Greetings => _greetingsProvider.Greetings;
public CheerfulService(GreetingsProvider greetingsProvider)
{
_greetingsProvider = greetingsProvider;
}
private readonly GreetingsProvider _greetingsProvider;
}
class GreetingsProvider
{
public string Greetings { get; set; }
}
9. RegisterInstance
注册已经存在的实例到容器。
void Main()
{
var container = new Container();
var a = new A();
container.RegisterInstance(a);
container.Register<B>();
var b = container.Resolve<B>();
Console.WriteLine(a == b.A); // True
}
class A { }
class B
{
public readonly A A;
public B(A a) { A = a; }
}
9.1 通过Use
方法将已存在的实例直接注入到当前作用域
void Main()
{
var container = new Container();
container.Register<B>();
using (var scope = container.OpenScope())
{
var a = new A();
scope.Use(a); // 注入到当前作用域
var b = scope.Resolve<B>();
Console.WriteLine(a == b.A); //True
}
var anotherA = new A();
container.Use(anotherA); // 注入到单例作用域
var anotherB = container.Resolve<B>();
Console.WriteLine(anotherA == anotherB.A); // True
}
class A { }
class B
{
public readonly A A;
public B(A a) { A = a; }
}
9.2 使用Use时指定服务类型
void Main()
{
var container = new Container();
// 编译时类型已知
var a = new A();
container.Use<ISomeService>(a);
// 运行时类型已知
object aa = a;
container.Use(typeof(ISomeService), aa);
}
interface ISomeService { }
class A : ISomeService { }
10. RegisterInitializer
该功能通过传入一个委托,该委托在解析方法返回前或依赖被注入前被调用。
void Main()
{
var container = new Container();
container.Register<Logger>(Reuse.Singleton);
container.Register<IService, MyService>();
container.RegisterInitializer<IService>((service, resolverContext) => resolverContext.Resolve<Logger>().Log("created"));
container.Resolve<IService>();
container.Resolve<Logger>().LogData.Dump();
}
interface IService { }
class MyService : IService { }
class Logger
{
public readonly List<string> LogData = new List<string>();
public void Log(string s) => LogData.Add(s);
}
上个例子中指定了服务的类型,如何实现对任意一个注册都有类似的日志功能?
void Main()
{
var container = new Container();
var loggerKey = "logger";
container.Register<Logger>(Reuse.Singleton, serviceKey: loggerKey);
container.Register<IService, MyService>();
container.RegisterInitializer<object>(
(anyObj, resolver) => resolver.Resolve<Logger>(loggerKey).Log("created object"),
condition: request => !loggerKey.Equals(request.ServiceKey));
container.Resolve<IService>();
container.Resolve<Logger>(loggerKey).LogData.Dump();
}
interface IService { }
class MyService : IService { }
class Logger
{
public readonly List<string> LogData = new List<string>();
public void Log(string s) => LogData.Add(s);
}
10.1 初始化使用的重用方式与实现对象的重用方式不同
默认情况下,初始化器装饰器使用的重用方式与实现对象的重用方式相同。在DryIOC v4.5.0
之后新增了一个reuse
参数重载,使得可以独立的控制重用方式。
void Main()
{
var container = new Container();
container.Register<IFoo, Boo>(Reuse.Singleton);
var scopedUsages = 0;
container.RegisterInitializer<IFoo>((x, r) => ++scopedUsages, Reuse.Scoped);
using (var scope = container.OpenScope())
scope.Resolve<IFoo>();
using (var scope = container.OpenScope())
scope.Resolve<IFoo>();
using (var scope = container.OpenScope())
scope.Resolve<IFoo>();
Console.WriteLine(scopedUsages);
}
interface IFoo { }
class Boo : IFoo { }
11. RegisterPlaceholder
有些时候,你可能尚没有服务实现或在之后实现。在这种情况下,可以使用RegisterPlaceholder<IService>()
,之后在实现类型之后,再将实现类型给与补上Register<IService, Foo>(ifAlreadyRegistered:IfAlreadyRegistered.Replace)
。
void Main()
{
var container = new Container();
container.RegisterPlaceholder<IService>();
var getService = container.Resolve<Func<IService>>();
container.Register<IService, Foo>(ifAlreadyRegistered: IfAlreadyRegistered.Replace);
Console.WriteLine(getService() is Foo);
}
interface IService { }
class Foo : IService { }
12. RegisterDisposer
通常的清理工作是实现IDisposable
接口。如果以Reuse
的重用方式注册实现IDisposable
接口的瞬态服务,当重用作用域被释放,接着服务亦被释放。
void Main()
{
var container = new Container();
container.Register<FileAbstraction>(Reuse.Singleton);
container.RegisterDisposer<FileAbstraction>(f => f.CloseFile());
var file = container.Resolve<FileAbstraction>();
file.ReadWriteStuff();
container.Dispose(); // will call disposer action for FileUser singleton
Console.WriteLine(file.IsClosed);
}
internal class FileAbstraction
{
public bool IsClosed { get; private set; }
public void CloseFile() => IsClosed = true;
public void ReadWriteStuff() { }
}
使用通用类型:
void Main()
{
var container = new Container();
container.Register<X>(Reuse.Singleton);
container.Register<Y>(Reuse.Singleton);
container.RegisterDisposer<IClosable>(closable => closable.Close());
var x = container.Resolve<X>();
var y = container.Resolve<Y>();
container.Dispose();
Console.WriteLine(x.IsClosed);
Console.WriteLine(y.IsClosed);
}
interface IClosable
{
bool IsClosed { get; }
void Close();
}
class X : IClosable
{
public bool IsClosed { get; private set; }
public void Close() => IsClosed = true;
}
class Y : IClosable
{
public bool IsClosed { get; private set; }
public void Close() => IsClosed = true;
}