假设我有一个服务,我想用scoped生命周期来解决。但有时我会尝试将其解析为接口类型,有时也会尝试将其解析为实现类型。
我尝试做的第一件事是:
ServiceCollection services;
services.AddScoped<MyClass>();
services.AddScoped<IMyInterface, MyClass>();
上述示例的问题是,如果我解析IMyInterface,则使用不同的实例,而不是解析MyClass。基本上,两个范围的实例可能同时存在。
我通过以下方式解决此问题。但它很容易出错,因为你很容易忘记在一个地方做这件事,而且很难注意到。
serviceCollection.AddScoped<MyClass>();
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>());
有没有办法以一种不易出错的方式完成我想要的东西。优先,但不一定,只需一次注册?
即。作为xUnit测试:
public class Tests
{
[Fact]
public void ReturnsSameInstanceForImplementationAndServiceType()
{
var serviceCollection = new ServiceCollection();
// TODO: Change these lines so they're less error prone.
serviceCollection.AddScoped<MyClass>();
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>());
var services = serviceCollection.BuildServiceProvider();
var myInt = services.GetRequiredService<IMyInterface>();
var myCls = services.GetRequiredService<MyClass>();
Assert.Equal(myCls, myInt);
}
class MyClass : IMyInterface { }
interface IMyInterface { }
}
答案 0 :(得分:5)
一种选择是创建自己的扩展方法,将您在问题中显示的两条线包装起来。例如:
class PropertyDetails extends React.Component {
static propTypes = {
breadcrumbChange: PropTypes.func,
folderId: PropTypes.string.isRequired
}
/**
* @typedef {Object} Props
* @property {function} breadcrumbChange
* @property {string} folderId
*/
/**
* @constructor
* @param {Props} props
*/
constructor(props) {
super(props);
您可以这样称呼:
public static class ServiceCollectionExtensions
{
public static void AddScopedInterfaceAndClass<TInterface, TClass>(this IServiceCollection serviceCollection)
where TInterface : class
where TClass : class, TInterface
{
serviceCollection.AddScoped<TClass>();
serviceCollection.AddScoped<TInterface, TClass>(sp => sp.GetRequiredService<TClass>());
}
}
我很欣赏serviceCollection.AddScopedInterfaceAndClass<IMyInterface, MyClass>();
并不是一个完美的名字 - 这只是展示这个想法的一个例子。此外,您还必须记住使用此扩展程序,而不是AddScopedInterfaceAndClass
。
注意:您可以通过删除第二个泛型(AddScoped
)来简化扩展方法中的第二个AddScoped
,因为这是由编译器推断的。