泛型注册
使用 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.Decorator
container.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 : SpecialEntity
where 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 A
var aHandlers = container.ResolveMany<IHandler<A>>();
// Assert通过,集合中包含 AHandler 和 BHandler,因为 IHandler<B> 通过协变类型继承自 IHandler<A>
Assert.AreEqual(2, aHandlers.Count());
// Assert通过,集合中仅包含 BHandler
var bHandlers = container.ResolveMany<IHandler<B>>();
Assert.AreEqual(1, bHandlers.Count());
}
// 通过 out 关键词,将 TEvent 参数声明为 “协变” 类型
public interface IHandler<out TEvent> { } // covariant handler
public 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 关键词,声明为“一般”泛型
```csharp
public interface IHandler<TEvent> { } // covariant handler
public 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通过,集合中仅包含 AHandler
var aHandlers = container.ResolveMany<IHandler<A>>();
Assert.AreEqual(1, aHandlers.Count());
}
public interface IHandler<out TEvent> { } // covariant handler
public class A { }
public class B : A { }
public class AHandler : IHandler<A> { }
public class BHandler : IHandler<B> { }
}