为什么在 C# 中使用一次性 pastern 时需要创建一个 属性 来检查资源是否已被释放?
Why do I need to create a property to check if a resource has been disposed when using disposable pastern in c#?
我需要编写一个 class,我想让消费者能够通过在 C# 中用 using(...)
语句包装代码来处理代码。
为此,我必须实现 Microsoft 的 IDisposable
接口。
基于Microsoft approach on implementing it,我应该这样做
一个通用接口
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#,所以我对这个实现有一些疑问。
问题
为什么我真的需要一个 属性 来告诉我对象是否已被处置,然后再处置它?
换句话说,我不能在处理之前检查 _context
是否为 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;
}
}
_context
不会 null
如果对象已经被释放。它仍然会引用已处置的对象。
现在,如果您无需存储布尔变量就可以确定您的对象是否已被释放,那很好。
你不应该实际拥有的是GC.SuppressFinalize
你的对象没有终结器,所以没有什么可以抑制的。
指示Dispose
已经被调用的字段(或属性)对于实现Dispose(bool)
方法本身不是强烈要求的,如以下规则所述:
✓ DO allow the Dispose(bool) method to be called more than once. The method might choose to do nothing after the first call.
如果您有其他方法/属性并且希望从同一文档中实施以下规则,则需要它:
✓ DO throw an ObjectDisposedException from any member that cannot be used after the object has been disposed of.
我想分享一下我对处置模式的看法。根据我的经验,您需要在 class 包含非托管资源或 class 被设计为继承的情况下使用该模式(即使它没有非托管资源只是为了提供对于将实现派生 classes 的程序员来说,这是众所周知的逻辑)。在大多数情况下,您似乎编写了一堆无用的代码。所以在大多数情况下你需要做的是:
public sealed class SomeClass : ISomeClass
{
private readonly TimeTrackerContext _context;
public void Dispose()
{
_context.Dispose();
}
}
第二个想法是处理 _context 字段本身。如果您通过构造函数传递上下文,您实际上并不知道是否真的需要处理它。 .NET Stream-based classes(如 StreamWriter)在 .NET 4.0 之前也一直存在这个问题。解决方案是编写 Stream 包装器(如 NonDisposableStreamWrapper),它在调用 dispose 时不处理内部流。真正解决这个问题的方法是在构造函数中添加额外的 dispose 字段,指定是否释放内部 class 。例如:
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();
}
}
}
我需要编写一个 class,我想让消费者能够通过在 C# 中用 using(...)
语句包装代码来处理代码。
为此,我必须实现 Microsoft 的 IDisposable
接口。
基于Microsoft approach on implementing it,我应该这样做
一个通用接口
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#,所以我对这个实现有一些疑问。
问题
为什么我真的需要一个 属性 来告诉我对象是否已被处置,然后再处置它?
换句话说,我不能在处理之前检查 _context
是否为 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;
}
}
_context
不会 null
如果对象已经被释放。它仍然会引用已处置的对象。
现在,如果您无需存储布尔变量就可以确定您的对象是否已被释放,那很好。
你不应该实际拥有的是GC.SuppressFinalize
你的对象没有终结器,所以没有什么可以抑制的。
指示Dispose
已经被调用的字段(或属性)对于实现Dispose(bool)
方法本身不是强烈要求的,如以下规则所述:
✓ DO allow the Dispose(bool) method to be called more than once. The method might choose to do nothing after the first call.
如果您有其他方法/属性并且希望从同一文档中实施以下规则,则需要它:
✓ DO throw an ObjectDisposedException from any member that cannot be used after the object has been disposed of.
我想分享一下我对处置模式的看法。根据我的经验,您需要在 class 包含非托管资源或 class 被设计为继承的情况下使用该模式(即使它没有非托管资源只是为了提供对于将实现派生 classes 的程序员来说,这是众所周知的逻辑)。在大多数情况下,您似乎编写了一堆无用的代码。所以在大多数情况下你需要做的是:
public sealed class SomeClass : ISomeClass
{
private readonly TimeTrackerContext _context;
public void Dispose()
{
_context.Dispose();
}
}
第二个想法是处理 _context 字段本身。如果您通过构造函数传递上下文,您实际上并不知道是否真的需要处理它。 .NET Stream-based classes(如 StreamWriter)在 .NET 4.0 之前也一直存在这个问题。解决方案是编写 Stream 包装器(如 NonDisposableStreamWrapper),它在调用 dispose 时不处理内部流。真正解决这个问题的方法是在构造函数中添加额外的 dispose 字段,指定是否释放内部 class 。例如:
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();
}
}
}