C# 如何确保不处置其他人仍在使用的对象

C# 如何确保不处置其他人仍在使用的对象,c#,.net,dependency-injection,dispose,C#,.net,Dependency Injection,Dispose,我有一个使用构造函数注入的类 public class MyClass { public MyClass(IInterface1 interface1) { } public Dispose() { interface1.dispose(); } } 接口1将由DI注入。但有时,我需要手动创建MyClass public class MyOtherClass {

我有一个使用构造函数注入的类

public class MyClass
{                       
    public MyClass(IInterface1 interface1)
    {            
    }

    public Dispose()
    {
       interface1.dispose();
    }
}
接口1将由DI注入。但有时,我需要手动创建MyClass

public class MyOtherClass
{                       
    private readonly IInterface1 _interface1;

    public MyOtherClass()
    {
      _interface1 = new Interface1();
    }       

    public Foo()
    {
       foo = new MyClass(_interface1);
       bar = new MyClass(_interface1);
    }
}
在我的dispose方法中,当MyClass被销毁时,interface1总是被释放。问题是,interface1由MyOtherClass拥有,并且可能仍被其他实例使用,因此不应予以处置。我如何解决这个问题?

你不应该打电话

interface1.dispose();
在我的班级里

如果interface1是由DI容器创建的,那么它将在那里重新创建。 如果您在MyOtherClass中显式创建它,请在MyOtherClass中处理它。

您不应该调用

interface1.dispose();
在我的班级里

如果interface1是由DI容器创建的,那么它将在那里重新创建。
如果要像在MyOtherClass中那样显式创建它,请在MyOtherClass中处理它。

您的代码有两个问题

首先,
MyClass
“非法”取得了
IInterface1
的所有权,但它不知道该实例的生存期是什么。这意味着如果重复使用
IInterface1
,系统将中断

所有权的基本规则是“创建实例的人负责处理它”(The)。因为
MyClass
没有创建
IInterface1
,所以他不应该处理它<因此,code>MyClass不应实现
Dispose
方法,也不应调用
IInterface1.Dispose()

其次,通过让
IInterface1
实现
IDisposable
,您的代码违反了(DIP),因为DIP声明:

抽象不应该依赖于细节。细节应视情况而定 抽象概念

但是,您的
IInterface1
取决于实现细节,因为某个组件是否具有需要处置的非托管资源是一个实现细节。该
IInterface1
的每个实现都不太可能总是需要处理资源,因此您的接口泄漏了特定实现的实现细节

因此,与其让
IInterface1
实现
IDisposable
,不如让给定的实现实现
IDisposable
。这样做的好处在于它最小化了
IInterface1
的API,这使得它更易于使用,并且可能允许您遵守API

如果您这样做,问题会立即消失,因为
MyClass
不知道
IInterface1
是否可以被释放(这很好),这意味着它首先不能意外调用
Dispose

当然,这就让创建该实例的系统部分来处理该实例(这很好)。如果此实例是由DI库(如果您使用DI库)代表您创建的,则DI库通常负责处理该实例。如果您不使用容器,您必须确保自己进行处理


请注意,并非所有容器都跟踪所有实例。例如,Unity和Simple Injector不会自动跟踪(和处理)瞬态实例。然而,在大多数情况下,一次性组件应该以限定的生活方式注册(按照web请求或类似的方式)。我认为在这种情况下,所有容器都会处理以这种方式注册的实例。

您的代码有两个问题

首先,
MyClass
“非法”取得了
IInterface1
的所有权,但它不知道该实例的生存期是什么。这意味着如果重复使用
IInterface1
,系统将中断

所有权的基本规则是“创建实例的人负责处理它”(The)。因为
MyClass
没有创建
IInterface1
,所以他不应该处理它<因此,code>MyClass不应实现
Dispose
方法,也不应调用
IInterface1.Dispose()

其次,通过让
IInterface1
实现
IDisposable
,您的代码违反了(DIP),因为DIP声明:

抽象不应该依赖于细节。细节应视情况而定 抽象概念

但是,您的
IInterface1
取决于实现细节,因为某个组件是否具有需要处置的非托管资源是一个实现细节。该
IInterface1
的每个实现都不太可能总是需要处理资源,因此您的接口泄漏了特定实现的实现细节

因此,与其让
IInterface1
实现
IDisposable
,不如让给定的实现实现
IDisposable
。这样做的好处在于它最小化了
IInterface1
的API,这使得它更易于使用,并且可能允许您遵守API

如果您这样做,问题会立即消失,因为
MyClass
不知道
IInterface1
是否可以被释放(这很好),这意味着它首先不能意外调用
Dispose

当然,这就让创建该实例的系统部分来处理该实例(这很好)。如果此实例是由DI库(如果您使用DI库)代表您创建的,则DI库通常负责处理该实例。如果您不使用容器,您必须确保自己进行处理

请注意,并非所有容器都跟踪所有实例。例如,Unity和Simple Injector不会自动跟踪(和处理)瞬态实例。然而,在大多数情况下,一次性组件应该以限定的生活方式注册(按照web请求或类似的方式)。我想在那种情况下,一切都包括在内