泛型注册
使用 Register 方法实现泛型注册
示例 :注册泛型类型
using System;using System.Linq;using DryIoc;using NUnit.Framework;class Register_open_generic{[Test]public void Example(){var container = new Container();// 这里在 Register 方法中传入 typeof(ICommand<>) 指定泛型类型container.Register(typeof(ICommand<>), typeof(DoSomethingCommand<>));var cmd = container.Resolve<ICommand<MyData>>();Assert.IsInstanceOf<DoSomethingCommand<MyData>>(cmd);}interface ICommand<T> { }class DoSomethingCommand<T> : ICommand<T> { }struct MyData { }}
示例 :注册泛型类型
class Open_generic_registrations{[Test]public void Example(){var container = new Container();// 默认注册container.Register(typeof(Command<>));// 这里使用 Reuse 指定服用方式container.Register(typeof(Command<>), Reuse.Singleton);// 这里使用 IfAlreadyRegistered.AppendNewImplementation,表示若类型已注册,则为该类型添加新的注册container.Register(typeof(ICommand<>), typeof(Command<>),ifAlreadyRegistered: IfAlreadyRegistered.AppendNewImplementation,serviceKey: "blah");// 这里使用 Setup.Decoratorcontainer.Register(typeof(ICommand<>), typeof(LoggingCommand<>),setup: Setup.Decorator);// etc.}interface ICommand<T> { }class Command<T> : ICommand<T> { }class LoggingCommand<T> : ICommand<T> { }}
解析单个服务类型时,封闭类型的注册优先级要高于对应的开发类型的注册:
示例 :解析泛型对象的优先级
class Closed_is_preferred_over_open_generic{[Test]public void Example(){var container = new Container();container.Register<A<int>, BInt>();container.Register(typeof(A<>), typeof(B<>));var a = container.Resolve<A<int>>(); // 这类解析出来的是 BInt 类型Assert.IsInstanceOf<BInt>(a);// 解析集合时(数组),将会解析该服务类注册的所有实现类,集合的数量等于实现类的注册数量。var items = container.Resolve<A<int>[]>();// Assert通过,数组中包含 Bint 与 B<int>Assert.AreEqual(2, items.Length);}class A<T> { }class BInt : A<int> { }class B<T> : A<T> { }}
匹配类型参数约束
在解析集合类型时,基于泛型约束条件实现过滤
示例 :泛型约束条件过滤
class Matching_open_generic_type_constraints{[Test]public void Example(){var container = new Container();// 同时注册两个类型,通过 nonPublicServiceTypes = true 允许非public服务类也可以注册container.RegisterMany(new[] { typeof(A<>), typeof(B<>) }, nonPublicServiceTypes: true);var items = container.Resolve<I<string>[]>();// Assert通过,受制于类型约束,string 类型并非继承自 IDisposable,因此无法解析 A<string> 对象,数组集合仅有一个 B<string> 类型对象。Assert.AreEqual(1, items.Length);Assert.IsInstanceOf<B<string>>(items[0]);}interface I<T> { }class A<T> : I<T> where T : IDisposable { }class B<T> : I<T> { }}
针对上述例子,假设 nonPublicServiceTypes = false (默认值),由于A
container.RegisterMany(new[] { typeof(A<>), typeof(B<>) }, nonPublicServiceTypes: false);
异常信息 :
DryIoc.ContainerException:“code: Error.NoServicesWereRegisteredByRegisterMany;
message: No service types were discovered in RegisterMany (or in RegisterInstanceMany) for the specified implementation types:
[ConsoleApp1.A<>,
ConsoleApp1.B<>]
Maybe you missed the implementation or service type(s), e.g. provided only abstract or compiler-generated implementation types, or specified a wrong serviceTypeCondition,or did not specify to use nonPublicServiceTypes, etc.”
**
从泛型约束中识别并填写类型参数
class Fill_in_type_arguments_from_constraints{[Test]public void Example(){var container = new Container();container.Register(typeof(ICommandHandler<>), typeof(UpdateCommandHandler<,>));var handler = container.Resolve<ICommandHandler<UpdateCommand<MyEntity>>>();Assert.IsInstanceOf<UpdateCommandHandler<MyEntity, UpdateCommand<MyEntity>>>(handler);}public interface ICommandHandler<TCommand> { }public class SpecialEntity { }public class UpdateCommand<TEntity> { }public class UpdateCommandHandler<TEntity, TCommand> : ICommandHandler<TCommand>where TEntity : SpecialEntitywhere TCommand : UpdateCommand<TEntity>{ }public class MyEntity : SpecialEntity { }}
从上述例子可以看出,DryIoc 十分智能,能够使用将 MyEntity 作为 UpdateCommandHandler 函数的首个参数类型。
支持“变体”泛型的解析
支持“协变”泛型(默认开启支持)
示例 :支持“协变”
class Generic_variance_thingy{[Test]public void Example(){var container = new Container();container.Register<IHandler<A>, AHandler>();container.Register<IHandler<B>, BHandler>();// get all handlers of Avar aHandlers = container.ResolveMany<IHandler<A>>();// Assert通过,集合中包含 AHandler 和 BHandler,因为 IHandler<B> 通过协变类型继承自 IHandler<A>Assert.AreEqual(2, aHandlers.Count());// Assert通过,集合中仅包含 BHandlervar bHandlers = container.ResolveMany<IHandler<B>>();Assert.AreEqual(1, bHandlers.Count());}// 通过 out 关键词,将 TEvent 参数声明为 “协变” 类型public interface IHandler<out TEvent> { } // covariant handlerpublic class A { }public class B : A { }public class AHandler : IHandler<A> { }public class BHandler : IHandler<B> { }}
关于“协变”泛型
具有协变类型参数的接口使其方法返回的类型可以比类型参数指定的类型派生程度更大。 例如,因为在 .NET Framework 4 的 IEnumerable
中,类型 T 是协变的,所以可以将 IEnumerable(Of String) 类型的对象分配给 IEnumerable(Of Object) 类型的对象,而无需使用任何特殊转换方法。
- 使用 out 关键词,声明为“协变”类型
```csharp
public interface IHandler
{ } // covariant handler public class A { } public class B : A { } public class AHandler : IHandler { } public class BHandler : IHandler { }
// Bhandler 可以隐式转换为 IHandler IHandler a = new BHandler();
- 移除 out 关键词,声明为“一般”泛型```csharppublic interface IHandler<TEvent> { } // covariant handlerpublic class A { }public class B : A { }public class AHandler : IHandler<A> { }public class BHandler : IHandler<B> { }// 抛出异常IHandler<A> a = new BHandler();
异常信息 :(编译时错误)
无法将类型“ConsoleApp1.BHandler”隐式转换为“ConsoleApp1.IHandler
**
关闭对“协变”泛型的支持
示例 :关闭“协变”支持
class Turn_off_generic_variance_in_collections{[Test]public void Example(){// 这里通过 WithoutVariantGenericTypesInResolvedCollection 方法,取消对变体泛型的支持var container = new Container(rules =>rules.WithoutVariantGenericTypesInResolvedCollection());container.Register<IHandler<A>, AHandler>();container.Register<IHandler<B>, BHandler>();// Assert通过,集合中仅包含 AHandlervar aHandlers = container.ResolveMany<IHandler<A>>();Assert.AreEqual(1, aHandlers.Count());}public interface IHandler<out TEvent> { } // covariant handlerpublic class A { }public class B : A { }public class AHandler : IHandler<A> { }public class BHandler : IHandler<B> { }}
