RegisterDelegate 方法

Registers a factory delegate for creating an instance of “TService”.ister

通过 RegisterDelegate 方法传入自定义的工厂方法

示例 :使用 RegisterDelegate 方法和自定义委托实现类型注册

  1. class Register_delegate
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. // 这里通过 RegisterDelegate 方法,传入一个匿名委托
  8. container.RegisterDelegate<IService>(resolverContext => new CheerfulService { Greetings = "Hey!" });
  9. var x = container.Resolve<IService>();
  10. Assert.AreEqual("Hey!", ((CheerfulService)x).Greetings);
  11. }
  12. internal class CheerfulService : IService
  13. {
  14. public string Greetings { get; set; }
  15. }
  16. }

IResolverContext 接口

  • 通过 RegisterDelegate 方法提供的 IResolverContext 参数,可以在解析对象的同时解析它所依赖的其他对象

    1. class Register_delegate_with_resolved_dependencies
    2. {
    3. [Test]
    4. public void Example()
    5. {
    6. var container = new Container();
    7. container.RegisterDelegate(_ => new GreetingsProvider { Greetings = "Mya" });
    8. // 在解析 CheerfulService 对象时,通过 resolverContext 参数解析它所依赖的 GreetingsProvider 对象
    9. container.RegisterDelegate<IService>(resolverContext => new CheerfulService(resolverContext.Resolve<GreetingsProvider>()));
    10. var x = container.Resolve<IService>();
    11. Assert.AreEqual("Mya", ((CheerfulService)x).Greetings);
    12. }
    13. class GreetingsProvider
    14. {
    15. public string Greetings { get; set; }
    16. }
    17. class CheerfulService : IService
    18. {
    19. public string Greetings => _greetingsProvider.Greetings;
    20. public CheerfulService(GreetingsProvider greetingsProvider)
    21. {
    22. _greetingsProvider = greetingsProvider;
    23. }
    24. private readonly GreetingsProvider _greetingsProvider;
    25. }
    26. }

虽然使用自定义委托注册类型的功能很强大,但并DryIoc官方并不推荐,理由如下:

  1. Memory leaks by capturing variables into delegate closure and keeping them for a container lifetime.
  2. Delegate is the black box for Container, mostly because it should use theResolvecall inside to resolve the dependency cutting of the object graph analysis, which makes it hard to find type mismatches or diagnose other potential problems. Among the un-catched problems are:

**
因此,尽量将它作为最后的选择。DryIoc 拥有很多更加有效的方法来覆盖自定义委托方法的需求。其中之一的选择是 FactoryMethod。

RegisterDelegate 方法的使用建议

将依赖对象作为 RegisterDelegate 方法的参数,由 DryIoc 的容器自动解析对象,而不是在委托内部手动解析对象(resolverContext.Resolve)。

  • 这些注入的依赖对象的生命周期由容器控制。
  • 由于不存在“黑箱操作”,因此“递归依赖”和“俘虏依赖”问题都能被容器捕获。

    1. class Register_delegate_with_parameters
    2. {
    3. [Test] public void Example()
    4. {
    5. var container = new Container();
    6. container.Register<A>(Reuse.Singleton);
    7. container.Register<B>(Reuse.Singleton);
    8. // 通过 RegisterDelegate 方法,同时注册 A,B 和 X
    9. container.RegisterDelegate<A, B, X>((a, b) => new X(a, b));
    10. Assert.IsNotNull(container.Resolve<X>());
    11. }
    12. class A {}
    13. class B {}
    14. class X
    15. {
    16. public X(A a, B b) {}
    17. }
    18. }

    当类型未知时,RegisterDelegate 会难以使用

    当编译时类型未知,委托将会变得很难用。因为一旦写成了 type = typeof(Foo 后将无法提供写入一个新的类型。为了处理这种情况,DryIoc 允许使用运行时类型:

    示例 :使用 RegisterDelegate 方法和自定义委托实现类型注册

    1. class Register_delegate_returning_object
    2. {
    3. [Test]
    4. public void Example()
    5. {
    6. var container = new Container();
    7. container.RegisterDelegate(typeof(IService), r => Activator.CreateInstance(typeof(Foo)));
    8. var x = container.Resolve<IService>();
    9. Assert.IsInstanceOf<Foo>(x);
    10. }
    11. class Foo : IService { }
    12. }

RegisterInstance 方法

RegisterInstance 允许将一个存在的实例对象注入到容器当中, 随后用于依赖注入。

示例 :使用 RegisterInstance 方法注册一个已存在的实例对象(Instance)

  1. class Register_instance_example
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. var a = new A();
  8. // 使用 RegisterInstance 方法将 a 对象注册进容器当中
  9. container.RegisterInstance(a);
  10. container.Register<B>();
  11. var b = container.Resolve<B>();
  12. // 容器解析 B 类对象时,需要为其构造函数解析一个 A 类对象,此时解析出来的 a 就是之前注册时提供的 a。
  13. Assert.AreSame(a, b.A);
  14. }
  15. class A { }
  16. class B
  17. {
  18. public readonly A A;
  19. public B(A a) { A = a; }
  20. }
  21. }

使用 Use 方法将实例注入作用域

使用 Use 方法可跳过注册要求直接将实例注入到作用域当中。

警告:通过 Use 方法注入实例不支持 serviceKey , Wrappers 和D ecorators,不过它能够更佳的性能和更少的内存损耗。

示例 :使用 Use 方法将实例注入作用域

  1. class Example_of_scoped_and_singleton_instance
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. container.Register<B>();
  8. // 这里通过 OpenScope 方法打开一个新的作用域
  9. using (var scope = container.OpenScope())
  10. {
  11. var a = new A();
  12. // 这里使用 Use 方法将 a 注入到容器当中(容器没有注册A类)
  13. scope.Use(a);
  14. // 解析 b 的时候将之前 Use 的 a 对象注入到 b 中
  15. var b = scope.Resolve<B>();
  16. Assert.AreSame(a, b.A);
  17. }
  18. var anotherA = new A();
  19. container.Use(anotherA); // injected into singleton scope
  20. var anotherB = container.Resolve<B>(); // will inject `anotherA`
  21. Assert.AreSame(anotherA, anotherB.A);
  22. }
  23. class A { }
  24. class B
  25. {
  26. public readonly A A;
  27. public B(A a) { A = a; }
  28. }
  29. }

示例 :使用 Use 方法将 object 实例注入作用域(指定运行时类型)

  1. class Typed_instance
  2. {
  3. public void Example()
  4. {
  5. var container = new Container();
  6. // compile-time known type
  7. var a = new A();
  8. container.Use<ISomeService>(a);
  9. // 运行时已知类型,例如,为 object类型的实例 提供一个 type 参数
  10. object aa = a;
  11. container.Use(typeof(ISomeService), aa);
  12. }
  13. interface ISomeService {}
  14. class A : ISomeService {}
  15. }

RegisterInitializer 方法

RegisterInitializer allows to pass the action to be invoked on created a service before returning it from resolve method, or before injecting it as dependency.

用于再解析过程中——即创建对象后,返回对象前执行初始化操作

示例 :使用 RegisterInitializer 方法为“特定类型”添加初始化操作

  1. class Register_initializer
  2. {
  3. [Test] public void Example()
  4. {
  5. var container = new Container();
  6. container.Register<Logger>(Reuse.Singleton);
  7. container.Register<IService, MyService>();
  8. // 注册时,使用 RegisterInitializer 方法为 Iservice 类型增加初始化操作(日志记录)
  9. container.RegisterInitializer<IService>(
  10. (service, resolver) => resolver.Resolve<Logger>().Log("created"));
  11. container.Resolve<IService>();
  12. Assert.AreEqual("created", container.Resolve<Logger>().LogData[0]);
  13. }
  14. class Logger
  15. {
  16. public readonly List<string> LogData = new List<string>();
  17. public void Log(string s) => LogData.Add(s);
  18. }
  19. interface IService {}
  20. class MyService: IService {}
  21. }

示例 :使用 RegisterInitializer 方法为“所有类型”添加初始化操作

  • RegisterInitializer 方法可利用 condition 参数设置自定义过滤条件:排除 Logger 类,否则陷入 StackOverflowException

    1. class Register_initializer_for_any_object
    2. {
    3. [Test] public void Example()
    4. {
    5. var container = new Container();
    6. var loggerKey = "logger";
    7. // 为 Logger 类手动设置了 serviceKey
    8. container.Register<Logger>(Reuse.Singleton, serviceKey: loggerKey);
    9. container.Register<IService, MyService>();
    10. // 使用 RegisterInitializer 方法,利用 condition 参数将 Logger 类型排除出去,即解析 Logger 类型不记录日志
    11. container.RegisterInitializer<object>(
    12. (anyObj, resolver) => resolver.Resolve<Logger>(loggerKey).Log("created object"),
    13. condition: request => !loggerKey.Equals(request.ServiceKey));
    14. container.Resolve<IService>();
    15. Assert.AreEqual("created object", container.Resolve<Logger>(loggerKey).LogData[0]);
    16. }
    17. class Logger
    18. {
    19. public readonly List<string> LogData = new List<string>();
    20. public void Log(string s) => LogData.Add(s);
    21. }
    22. interface IService { }
    23. class MyService : IService { }
    24. }

    RegisterInitializer() 方法不仅仅适用于服务类型,还能适用于接口:

    1. container.RegisterInitializer<IDisposable>(
    2. (disposable, resolver) => resolver.Resolve<Logger>().Log("resolved disposable " + disposable));

    使用 Reuse 参数控制不同的初始化行为

    RegisterInitializer (DryIoc v4.5.0)提供 reuse 参数,用于控制不同作用域之间的初始话执行次数。

    示例 :使用 RegisterInitializer 方法配合 Reuse.Scoped

    1. class RegisterInitializer_with_reuse_different_from_initialized_object
    2. {
    3. [Test] public void Example()
    4. {
    5. var container = new Container();
    6. container.Register<IFoo, Boo>(Reuse.Singleton);
    7. var scopedUsages = 0;
    8. container.RegisterInitializer<IFoo>((x, r) => ++scopedUsages, Reuse.Scoped);
    9. using (var scope = container.OpenScope())
    10. scope.Resolve<IFoo>();
    11. using (var scope = container.OpenScope())
    12. scope.Resolve<IFoo>();
    13. using (var scope = container.OpenScope())
    14. scope.Resolve<IFoo>();
    15. Assert.AreEqual(3, scopedUsages);
    16. }
    17. interface IFoo { }
    18. class Boo : IFoo { }
    19. }

RegisterPlaceholder 方法

Register a service without implementation which can be provided later in terms of normal registration with IfAlreadyRegistered.Replace parameter. When the implementation is still not provided when the placeholder service is accessed,then the exception will be thrown. 可在无服务类的情况下实现注册,随后使用 IfAlreadyRegistered 参数替换成“常规”注册即可。在未替换成“常规”注册前解析服务对象,将会抛出异常。

This feature allows you to postpone decision on implementation until it is later known. 这特性能够推迟类型注册,直到你直到确切的实现类型。

示例 :延迟注册

  1. class Register_placeholder
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. container.RegisterPlaceholder<IService>();
  8. var getService = container.Resolve<Func<IService>>();
  9. IService service;
  10. // Assert通过,因为 IService 还未正在注册导致异常
  11. Assert.Throws<ContainerException>(() => service = getService());
  12. // 注册时使用 IfAlreadyRegistered.Replace,用于实现注册替换
  13. container.Register<IService, Foo>(ifAlreadyRegistered: IfAlreadyRegistered.Replace);
  14. service = getService();
  15. Assert.IsInstanceOf<Foo>(service);
  16. }
  17. interface IService { }
  18. class Foo : IService { }
  19. }

RegisterDisposer 方法

关于对象的生命周期:

The normal way to cleanup things is to implement IDisposable interface. If disposable service was registered with Reuse, and reuse scope is disposed, then the service will be disposed as well. For instance, registered singleton will be disposed when container (and therefore singleton scope) is disposed. 通常情况下,继承自 IDisposable 接口的实例对象会随着 reuse scope 释放而释放,singleton 对象会随着 container 释放而释放。

RegisterDispose 方法适用性:

But what if service for some reason does not implement IDisposable but still wants to invoke “release logic” when goes out of the scope. RegisterDisposer addresses such a need. 针对无法继承自 IDisposable 接口的实例对象,可通过 RegisterDispose 方法实现(逻辑) “释放”。

示例 :在 RegisterDisposer 方法中为“实现类”执行“逻辑”释放操作

  1. class Register_disposer
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. container.Register<FileAbstraction>(Reuse.Singleton);
  8. // 这里通过 RegisterDisposer 方法为 FileAbstraction 类注册释放时操作 CloseFile
  9. container.RegisterDisposer<FileAbstraction>(f => f.CloseFile());
  10. var file = container.Resolve<FileAbstraction>();
  11. file.ReadWriteStuff();
  12. // 容器释放,调用 file 的 CloseFile 方法
  13. container.Dispose();
  14. Assert.IsTrue(file.IsClosed);
  15. }
  16. internal class FileAbstraction
  17. {
  18. public bool IsClosed { get; private set; }
  19. public void CloseFile() => IsClosed = true;
  20. public void ReadWriteStuff() { }
  21. }
  22. }

示例 :在 RegisterDisposer 方法中为“服务类(接口)”执行“逻辑”释放操作

  1. class Register_disposer_for_many_services
  2. {
  3. [Test]
  4. public void Example()
  5. {
  6. var container = new Container();
  7. container.Register<X>(Reuse.Singleton);
  8. container.Register<Y>(Reuse.Singleton);
  9. // 这里 RegisterDisposer 方法注册的时 IClosable 接口
  10. container.RegisterDisposer<IClosable>(closable => closable.Close());
  11. var x = container.Resolve<X>();
  12. var y = container.Resolve<Y>();
  13. container.Dispose();
  14. Assert.IsTrue(x.IsClosed);
  15. Assert.IsTrue(y.IsClosed);
  16. }
  17. interface IClosable
  18. {
  19. bool IsClosed { get; }
  20. void Close();
  21. }
  22. class X : IClosable
  23. {
  24. public bool IsClosed { get; private set; }
  25. public void Close() => IsClosed = true;
  26. }
  27. class Y : IClosable
  28. {
  29. public bool IsClosed { get; private set; }
  30. public void Close() => IsClosed = true;
  31. }
  32. }

RegisterDisposer 方法支持利用 condition 参数设置条件

示例 :在 RegisterDisposer 方法中利用 condition 参数设置自定义过滤条件

  1. container.RegisterDisposer<IClosable>(closable => closable.Close(),
  2. condition: request => !request.GetKnownImplementationOrServiceType().IsAssignableTo<IDisposable>());