我需要强制使用“using”来处理类的新实例。
public class MyClass : IDisposable
{
...
}
using(MyClass obj = new MyClass()) // Force to use "using"
{
}
答案 0 :(得分:45)
您需要以确保放置对象的事实表明存在设计缺陷。如果处理是礼貌或高效的事情,那就没关系,但它不应该是语义上的必要。
没有办法强制通过using
语句处理对象。但是,您可以做的是在对象中维护一个标志,指示对象是否被处置,然后编写一个检查该标志的终结器。如果终结器检测到对象未被处理,那么您可以使用终结器,例如,通过failfast终止该进程。也就是说,严重惩罚那些忽略处置对象的用户,他们被迫修复他们的错误或停止使用你的对象。
这并不会让我感觉良好,善良或有礼貌,但你是唯一一个知道未能处置对象的可怕后果的人。是否对不遵守你的疯狂规则的人施加惩罚比对他们不遵守规则的后果生活更好是由你来决定的。
答案 1 :(得分:21)
这很难看,但你可以这样做:
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);
}
}
}
答案 2 :(得分:13)
您可以使用Roslyn框架编写自己的警告/错误。您的DiagnosticAnalyzer
会检查所有构造函数调用,以查看您的类是否正在构建,以及您是否在using
语句中。
报告的诊断可以设置为“错误”严重性,并且可以标记为不可配置,这意味着没有人可以将其降级为警告或信息。
此外,如果您正在开发Nuget库,您可能希望将您的分析器作为开发依赖项发送,并将其添加为分析器nuget包。这将导致您的所有用户被迫处置您的给定类。此包装称为"code-aware library"。
请注意,从理论上讲,这也可以由第三方分析器库(例如FxCop)完成,但是有许多IDisposable
实现并不需要严格处理,例如MemoryStream
,Dispose
并没有做很多事情,所以这些规则要么有一些白名单机制,要么报告误报。
答案 3 :(得分:5)
using语句是编译器从以下语言转换的简写:
(using DisposableObject d = new DisposableObject()){}
成:
DisposableObject d = new DisposableObject()
try
{
}
finally
{
if(d != null) d.Dispose();
}
所以你或多或少会问是否可以强制编写一个调用Dispose for object的try / finally块。
答案 4 :(得分:4)
我想知道FXCop是否可以执行该规则?
答案 5 :(得分:1)
不,你不能这样做。你甚至不能强迫他们打电话处理。您可以做的最好的事情是添加终结器。请记住,在处理对象时,终结器将被调用,直到运行时。
答案 6 :(得分:1)
不,不可能。现在你可以做的是在类的终结器中调用dispose方法(然后你可以在实际调用dispose方法时禁止使用它)。这样,如果没有在代码中明确地完成,它将触发。
此链接将向您展示如何实现终结器/配置模式:
答案 7 :(得分:0)
如果你想强制在这个类上使用,你的代码可以支持这个类,你可以在其他类中编码并隐藏MyClass以供正常使用。
答案 8 :(得分:0)
您应该查看RAII,这是一种确保获取的资源得到妥善处理的技术。
我的意思是,如果您不能强制调用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
答案 9 :(得分:0)
如果您想强制使用范围来处理资源,则可能不需要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
}
您只能以这种方式使用资源:
public void foo()
{
ResourceHandle resourceHandle = new ResourceHandle("parms");
resourceHandle.UseResource(delegate(Resource resource)
{
// use resource
});
}
如你所见,这里并不真正需要IDisposable。