一次性课程是否可以强制使用“using”?

问题描述 投票:0回答:11

我需要强制使用“using”来处置类的新实例。

public class MyClass : IDisposable
{
   ...
}

using(MyClass obj = new MyClass()) // Force to use "using"
{
}
c# dispose idisposable using
11个回答
50
投票

需要以确保对象被处置这一事实表明存在设计缺陷。如果处置是“礼貌”或“高效”的事情,那没问题,但它不应该是“语义上必要的”。 无法强制通过 using 语句处置对象。但是,您可以做的是在对象中维护一个标志,指示该对象是否已释放,然后编写一个终结器来检查该标志。如果终结器检测到对象没有被释放,那么你可以让终结器通过故障快速终止进程。也就是说,对疏忽处置该对象的用户进行严厉惩罚,迫使他们要么修复错误,要么停止使用您的对象。 我觉得这不太好、很好或很有礼貌,但你是唯一一个知道不处理该物体会带来什么可怕后果的人。对那些不遵守你的疯狂规则的人实施惩罚是否比承受他们不遵守规则的后果更好,这由你决定。

这很丑陋,但你可以做这样的事情:

public sealed class DisposableClass : IDisposable { private DisposableClass() { } public void Dispose() { //Dispose... } public static void DoSomething(Action<DisposableClass> doSomething) { using (var disposable = new DisposableClass()) { doSomething(disposable); } } }


23
投票

您可以使用 Roslyn 框架编写自己的警告/错误。您的

DiagnosticAnalyzer
 将检查所有构造函数调用,以查看您的类是否正在构造,以及您是否位于 
using

18
投票

报告的诊断可以设置为错误严重性,并且可以标记为不可配置,这意味着没有人可以将其降级为警告或信息。


此外,如果您正在开发 Nuget 库,您可能希望将分析器作为开发依赖项提供,并将其添加为分析器 nuget 包。这将导致您的所有用户被迫处置您给定的类。此包装称为
“代码感知库”

请注意,理论上这也可以由第三方分析器库(例如 FxCop)来完成,但是有许多

IDisposable

实现并不严格需要处理,例如 MemoryStream,其

Dispose

不做的事情并不多,因此这些规则要么有一些白名单机制,要么报告误报。

    
我想知道 
FXCop
是否可以执行该规则?


5
投票

using 语句是编译器转换而来的简写: (using DisposableObject d = new DisposableObject()){}


5
投票

DisposableObject d = new DisposableObject() try { } finally { if(d != null) d.Dispose(); }

所以你或多或少会问是否可以强制编写一个为对象调用 Dispose 的 try/finally 块。

不,你不能那样做。你甚至不能强迫他们调用 dispose。你能做的最好的事情就是添加一个终结器。请记住,当对象被释放时,终结器将被调用,这取决于运行时。


1
投票

此链接将向您展示如何实现终结器/处置模式:


1
投票
http://www.devx.com/dotnet/Article/33167

如果你想在这个类上强制使用using,你的代码支持这个类,你可以在其他类中编写代码并隐藏MyClass以供正常使用。


0
投票
RAII

,这是一种确保正确处置所获取的资源的技术。


0
投票
Dispose

方法(通过 using 或直接),你可以将其内容放在另一个将被调用的方法中,例如析构函数。

这是实现

IDisposable
的常见模式,如下所示:

// Implement IDisposable. // Do not make this method virtual. // A derived class should not be able to override this method. public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user's code. Managed and unmanaged resources // can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be disposed. private void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) { // Dispose managed resources. component.Dispose(); } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. // TODO: write code } disposed = true; } // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. // Do not provide destructors in types derived from this class. ~ClassName() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false); }

来源:

http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize.aspx


如果你想强制处置某个范围内的资源,这是可能的,但 IDisposable 并不是真正需要的。使用以下代码: public class ResourceHandle { public delegate void ResourceProvider(Resource resource); private string _parms; public ResourceHandle(string parms) { _parms = parms; } public void UseResource(ResourceProvider useResource) { Resource resource = new Resource(_parms); useResource(resource); resource.Close(); } } public class Resource { private string _parms; internal Resource(string parms) { // Initialize resource } internal void Close() { // Do cleaning } // Public methods of resource }


0
投票

public void foo() { ResourceHandle resourceHandle = new ResourceHandle("parms"); resourceHandle.UseResource(delegate(Resource resource) { // use resource }); }

如您所见,这里并不真正需要 IDisposable。

Microsoft 添加了
代码分析规则 C2000

,默认情况下禁用,用于检查此项。


0
投票
创建了一个IDisposable类型的本地对象,但是该对象是 在对象的所有引用超出范围之前不会被释放。

不确定他们什么时候添加的。

它可能仅适用于 .NET Core 5.0 及更高版本。

您可以通过将以下内容添加到 .editorconfig 文件来启用它:

dotnet_diagnostic.CA2000.severity = error 似乎对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.