C# 在c中使用一次性pastern时,为什么需要创建一个属性来检查资源是否已被释放?

C# 在c中使用一次性pastern时,为什么需要创建一个属性来检查资源是否已被释放?,c#,.net,dispose,idisposable,C#,.net,Dispose,Idisposable,我需要编写一个类,在这个类中,我希望消费者能够通过使用。。。C.中的陈述 为此,我必须实现Microsoft的IDisposable接口 根据我的想法,我应该这样做 这样做的通用接口 public interface ISomeClass : IDisposable { // ... some methods to include } public class SomeClass : ISomeClass { private readonly TimeTrackerCont

我需要编写一个类,在这个类中,我希望消费者能够通过使用。。。C.中的陈述

为此,我必须实现Microsoft的IDisposable接口

根据我的想法,我应该这样做

这样做的通用接口

public interface ISomeClass : IDisposable
{
     // ... some methods to include
}

public class SomeClass : ISomeClass
{
     private readonly TimeTrackerContext _context;

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed && disposing && _context != null)
        {
            _context.Dispose();

        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
我正试图用正确的方法学习C,所以我对这个实现有一些疑问

问题:

为什么我真的需要有一个属性来告诉我,在我处置之前,该对象是否已被处置

换句话说,我不能在处理它之前检查一下_上下文是否为null吗?像这样的

public class SomeClass : ISomeClass
{
    private readonly TimeTrackerContext _context;

    private void SelfDisposing()
    {
        if (_context != null)
        {
            _context.Dispose();
        }

    }

    public void Dispose()
    {
        SelfDisposing();
        GC.SuppressFinalize(this);
    }

    private void SelfDisposing(bool disposing)
    {
        if (_context != null && !this.disposed && disposing)
        {
            _context.Dispose();
        }

        this.disposed = true;
    }
}
_如果对象已被释放,则上下文不会为null。它仍将引用已释放的对象

现在,如果您可以确定是否在不需要存储布尔变量的情况下处理对象,那么就可以了


实际上,您不应该使用GC.SuppressFinalize。您的对象没有终结器,因此没有要禁止的内容。

表示已调用Dispose的字段或属性对于实现Disposebool方法本身不是很必要的,如以下规则所述:

✓ 一定要允许多次调用Disposebool方法。该方法可能会选择在第一次调用后不执行任何操作

如果您有其他方法/属性,并且希望从同一文档中实现以下规则,则需要该方法:

✓ 不要从任何成员抛出ObjectDisposedException,该成员在对象被释放后无法使用


我想和大家分享一下我对这一模式的看法。根据我的经验,当一个类包含非托管资源,或者该类被设计为继承,即使它没有非托管资源,也只是为了为实现派生类的程序员提供众所周知的逻辑时,您需要在这种情况下使用该模式。在大多数情况下,您似乎编写了一堆无用的代码。因此,在大多数情况下,您需要做的是:

public sealed class SomeClass : ISomeClass
{
    private readonly TimeTrackerContext _context;

    public void Dispose()
    {
        _context.Dispose();
    }
}
第二个想法是处理_上下文字段本身。若你们通过构造函数传递上下文,你们实际上不知道你们是否真的需要处理它。基于NET流的类,如StreamWriter,在.NET4.0之前也一直存在这个问题。解决方案是编写流包装器,比如非DisposableStreamWrapper,在调用dispose时不处理内部流。这个问题的真正好的解决方案是在构造函数中添加额外的dispose字段,它指定是否处理内部类。例如:

public sealed class SomeClass : ISomeClass
{
    private readonly TimeTrackerContext _context;
    private bool _dispose;

    public SomeClass(TimeTrackerContext context, bool dispose = true)
    {
        _context = context;
        _dispose = dispose;
    }

    public void Dispose()
    {
        if (_dispose)
        {
            _context.Dispose();
        }
    }
}

可以,但在处理完上下文后,您不会将其设置为null,因此当它为null时,dispose会这样做吗?因为整个对象不再在内存中?不,dispose会按照您的指示执行。您没有将上下文设置为null,因此它不会为null。disposed是一个字段,而不是属性。@Igor这是一个输入错误。我修好了,这就解释了!关于GC.com,微软在文档中有漏洞✓ 请实现基本的Dispose模式,并在包含需要显式释放的资源且没有终结器的类型上提供终结器。@MikeA在包含需要显式释放的资源的类型上,您没有保留任何需要显式释放的资源,因此,您不需要终结器,也没有终结器。很可能你一生中永远都不需要编写终结器,即使你需要不时地创建一次性对象,你应该只需要这样做,因为你正在封装其他一次性对象。@MikeA,请看。提供了MicrosoftDispose模式,它在任何人都可以从您的类派生并自己提供终结器的情况下都是健壮的。在这种情况下,可以在基类中调用GC.SuppressFinalize,即使它本身没有终结器。您几乎可以肯定不需要它,并且可能应该将类密封起来,这样您就不必担心继承问题。因此,如果您封装了其他一次性对象,您就永远不需要编写终结器,因为这些对象应该有自己的终结器(如有必要)?+1感谢您提供此信息。为什么他们在这里使用虚拟方法而不是重写?根据我的理解,virtual将允许其他人重写这个方法,在我的情况下,应该重写它吗?他们使用virtual,因为示例中的类就是实现该模式的类。重写将在从该类继承的类(如果有的话)中使用。