.NET的依赖注入框架Microsoft.Extensions.DependencyInjection,支持注入未绑定的泛型类(Unbound generic type)
C#的关键字typeof可以用来获取未绑定的泛型类/接口(Unbound generic type)的Type类实例,未绑定的泛型类/接口(Unbound generic type)就是指没有指定类型参数的泛型类/接口,如下代码所示:
using System; namespace NET5UnboundGenericDependencyInjectionDemos { /// <summary> /// 泛型类Container<T> /// </summary> /// <typeparam name="T">泛型类型参数</typeparam> class Container<T> { } class Program { static void Main(string[] args) { Type unboundGenericType = typeof(Container<>);//通过typeof关键字,获取未绑定的泛型类Container<T>的Type类实例 Console.WriteLine(unboundGenericType.ToString()); Console.WriteLine("Press any key to end..."); Console.ReadKey(); } } }
运行上面代码,结果如下:
可以看到Type类实例unboundGenericType输出的信息中,泛型类Container<T>的类型参数T,并没有被指定为具体的类型,所以是未绑定的泛型类。
未绑定的泛型类常常被用于依赖注入中,这样可以大大增加代码的复用性,而微软的依赖注入框架Microsoft.Extensions.DependencyInjection支持注入未绑定的泛型类。
首先我们创建一个.NET 5.0控制台项目,然后引入nuget包:Microsoft.Extensions.DependencyInjection
项目的代码如下所示:
using Microsoft.Extensions.DependencyInjection; using System; namespace NET5UnboundGenericDependencyInjectionDemos { /// <summary> /// 泛型接口IContainer<T> /// </summary> /// <typeparam name="T">泛型类型参数,where T : new()约束保证类型T具有公共无参数构造函数</typeparam> interface IContainer<T> where T : new() { T Element { get; } /// <summary> /// 显示泛型类型参数T的Type类型 /// </summary> void ShowElementType(); } /// <summary> /// 泛型类Container<T>,实现接口IContainer<T> /// </summary> /// <typeparam name="T">泛型类型参数,where T : new()约束保证类型T具有公共无参数构造函数</typeparam> class Container<T> : IContainer<T> where T : new() { protected T element; public Container() { element = new T(); } public T Element { get { return element; } } /// <summary> /// 显示泛型类型参数T的Type类型 /// </summary> public void ShowElementType() { Console.WriteLine(element.GetType().ToString()); } } /// <summary> /// 类People,作为泛型接口IContainer<T>和泛型类Container<T>的类型参数T /// </summary> class People { public void Speak() { Console.WriteLine("I'm a people!"); } } class Program { static void Main(string[] args) { IServiceCollection serviceDescriptors = new ServiceCollection(); serviceDescriptors.AddTransient(typeof(IContainer<>), typeof(Container<>));//注册未绑定的泛型接口IContainer<T>和未绑定的泛型类Container<T>的依赖注入关系 IContainer<People> container = null;//声明关闭的泛型接口IContainer<People>变量container,下面使用依赖注入来为其赋值 using (ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider()) { using (IServiceScope serviceScope = serviceProvider.CreateScope()) { container = serviceScope.ServiceProvider.GetService<IContainer<People>>();//使用依赖注入为泛型接口IContainer<People>变量container赋值,依赖注入框架Microsoft.Extensions.DependencyInjection会构造一个关闭的泛型类Container<People>实例,赋值给IContainer<People> container } } Console.WriteLine(container.GetType().ToString());//显示泛型接口IContainer<People>变量container的实际类型 container.ShowElementType();//调用泛型接口IContainer<People>的ShowElementType方法 container.Element.Speak();//调用泛型接口IContainer<People>的类型参数People的Speak方法 Console.WriteLine("Press any key to end..."); Console.ReadKey(); } } }
运行上面代码,结果如下:
我们可以看到,使用依赖注入框架Microsoft.Extensions.DependencyInjection,我们可以为关闭的泛型接口(Closed generic type)IContainer<People>,来注入关闭的泛型类(Closed generic type)Container<People>,关闭的泛型类/接口(Closed generic type)就是指指定了具体类型参数的泛型类/接口,上面代码中泛型的类型参数就是People类。
注意上面代码中,我们在注册依赖注入关系的时候(AddTransient),是注册的未绑定的泛型接口IContainer<T>和未绑定的泛型类Container<T>的依赖注入关系,但是依赖注入框架Microsoft.Extensions.DependencyInjection,还是可以为关闭的泛型接口IContainer<People>,获得关闭的泛型类Container<People>。