具有继承接口的 .NET Core 依赖注入
.NET Core Dependency Injection with inherited interface
我有 I1
、I2
和 Class Foo
,其中 I2
继承了 I1
(I2
:I1
) 和 I2
在 Foo
中实现。我想注册一个范围内的依赖项,以便在单个范围内引用任何接口时始终 return 相同的 Foo
对象。
我尝试使用以下注册进行此操作,但它在同一范围内产生了 Foo
的三个不同实例:
services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
我的定义如下:
interface I1
{
GetData();
}
interface I2 : I1
{
string Data { set; }
}
class Foo : I2
{
private string myData;
public string Data { set => myData = value; }
public string GetData() => this.myData;
}
功能使用。
class Bar
{
private I2 _i2;
public Bar(I2 i2) => _i2 = i2;
public void SetData() => _i2.myData = "My Data";
}
class AnotherBar
{
private I1 _i1;
public AnotherBar(I1 i1) => _i1 = i1;
public string GetData() => _i1.GetData();
}
来自 AnotherBar
的 GetData()
将 return 在相同范围内设置在 Bar-SetData()
的相同数据?
这是使用 MS.DI 时需要注意的常见陷阱。这个陷阱叫做Torn Lifestyle。在 MS.DI 的情况下,每个注册都有自己的缓存。这意味着您的三个注册:
services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
每个都有自己的缓存和自己的实例。所以这意味着以下断言成立:
using (var scope = provider.CreateScope())
{
Assert.AreSame(scope.GetService<I1>(), scope.GetService<I1>());
Assert.AreSame(scope.GetService<I2>(), scope.GetService<I2>());
Assert.AreNotSame(scope.GetService<I1>(), scope.GetService<I2>());
}
要解决此问题,您必须将注册重写为以下内容:
services.AddScoped<Foo>();
services.AddScoped<I1>(c => c.GetRequiredService<Foo>());
services.AddScoped<I2>(c => c.GetRequiredService<Foo>());
在这种情况下,每个注册仍然有自己的缓存,但由于第二个和第三个请求原始 Foo
服务,这确保所有三个注册 return 同一范围内的同一实例.
我有 I1
、I2
和 Class Foo
,其中 I2
继承了 I1
(I2
:I1
) 和 I2
在 Foo
中实现。我想注册一个范围内的依赖项,以便在单个范围内引用任何接口时始终 return 相同的 Foo
对象。
我尝试使用以下注册进行此操作,但它在同一范围内产生了 Foo
的三个不同实例:
services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
我的定义如下:
interface I1
{
GetData();
}
interface I2 : I1
{
string Data { set; }
}
class Foo : I2
{
private string myData;
public string Data { set => myData = value; }
public string GetData() => this.myData;
}
功能使用。
class Bar
{
private I2 _i2;
public Bar(I2 i2) => _i2 = i2;
public void SetData() => _i2.myData = "My Data";
}
class AnotherBar
{
private I1 _i1;
public AnotherBar(I1 i1) => _i1 = i1;
public string GetData() => _i1.GetData();
}
来自 AnotherBar
的 GetData()
将 return 在相同范围内设置在 Bar-SetData()
的相同数据?
这是使用 MS.DI 时需要注意的常见陷阱。这个陷阱叫做Torn Lifestyle。在 MS.DI 的情况下,每个注册都有自己的缓存。这意味着您的三个注册:
services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
每个都有自己的缓存和自己的实例。所以这意味着以下断言成立:
using (var scope = provider.CreateScope())
{
Assert.AreSame(scope.GetService<I1>(), scope.GetService<I1>());
Assert.AreSame(scope.GetService<I2>(), scope.GetService<I2>());
Assert.AreNotSame(scope.GetService<I1>(), scope.GetService<I2>());
}
要解决此问题,您必须将注册重写为以下内容:
services.AddScoped<Foo>();
services.AddScoped<I1>(c => c.GetRequiredService<Foo>());
services.AddScoped<I2>(c => c.GetRequiredService<Foo>());
在这种情况下,每个注册仍然有自己的缓存,但由于第二个和第三个请求原始 Foo
服务,这确保所有三个注册 return 同一范围内的同一实例.