![](/img/trans.png)
[英]How to migrate C# MVC5 Global.asax to ASP.NET Core Startup.cs
[英]Question about C# Pattern in ASP.NET Core When Adding Services in Startup.cs
关于此代码来配置服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IDb, Db>();
services.AddControllers();
}
特别是这一行:
services.AddSingleton<IDb, Db>();
如果 AddSingleton 不是像代码片段中那样是具有 0 个参数的通用 function ,是否会有任何语义差异
AddSingleton(Type type1, Type type2);
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))
都没有区别。 两次调用都将产生完全相同的结果。
有一个通用重载的原因是它感觉好多了。 泛型方法优于传递类型,因为您可以更轻松地编写它。 因此,您更有可能看到通用用法。
此外,您可以向泛型类型 arguments 添加约束,这可能会增加一些编译时检查。 在这种特殊情况下,约束如下所示:
where TService : class
where TImplementation : class, TService
除了这两种类型都必须是引用类型之外,还有一个额外的要求,即TImplementation
继承自TService
。 这确保您可以在需要TImplementation
的地方实际使用TService
类型的实例。 这也是里氏替换原则背后的理念。 通过具有类型约束,此检查将在编译时进行验证,因此您可以确保这将在运行时工作,因为如果您使用其他重载则无法保证这一点。
不用说, AddTransient<>
和AddScoped<>
在它们各自的非泛型重载上的工作方式相同。
从语义上讲,两者的含义相同。 但是,使用泛型方法的一个优点是可以在编译时强制对传递给方法调用的类型进行约束。
在此方法的文档中,请注意约束, where TImplementation: class, TService
。 编译器可以在编译时检查Db
类型是否实现了IDb
并且是 class。
使用非泛型方法,这在编译时是不可能的。 (相反,它可以在运行时检查,并且可能会引发运行时错误。)
如果你搜索微软的文档,你会发现所有 Addsingleton 的工作方式都是一样的,唯一不同的是条目:
AddSingleton :将 TService 中指定的类型的 singleton 服务与 TImplementation 中指定的实现类型添加到指定的 IServiceCollection。
AddSingleton(IServiceCollection, Type, Type):将 serviceType 中指定类型的 singleton 服务与 implementationType 中指定的类型的实现添加到指定的 IServiceCollection。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.