的实现AddSingleton<T1, T2>
看起来像这样:
public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
return services.AddSingleton(typeof(TService), typeof(TImplementation));
}
如您所见,它实际上调用了AddSingleton
传递两种类型的另一个重载。因此,从语义上讲,您是否执行AddSingleton<IDb, Db>()
或. 都没有区别AddSingleton(typeof(IDb), typeof(Db))
。两次调用都将产生完全相同的结果。
有一个通用重载的原因是它感觉好多了。泛型方法优于传递类型,因为您可以更轻松地编写它。因此,您更有可能看到通用用法。
此外,您可以为泛型类型参数添加约束,这可能会添加一些编译时检查。在这种特殊情况下,约束如下所示:
where TService : class
where TImplementation : class, TService
除了这两种类型都必须是引用类型之外,还有一个额外的要求是TImplementation
继承自TService
. 这确保您可以在预期TImplementation
a 的地方实际使用类型的实例。TService
这也是里氏替换原则背后的理念。通过具有类型约束,此检查将在编译时进行验证,因此您可以确保这将在运行时工作,因为如果您使用其他重载则无法保证这一点。
不用说,AddTransient<>
并AddScoped<>
以相同的方式处理它们各自的非泛型重载。