40

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

public class MyClass : IDisposable
{
   ...
}

using(MyClass obj = new MyClass()) // Force to use "using"
{
}
4

10 回答 10

46

您需要确保处理对象这一事实表明存在设计缺陷。如果处理是礼貌高效的事情,那很好,但它在语义上不应该是必要的。

没有办法强制通过using语句处理对象。但是,您可以做的是在对象中维护一个标志,指示该对象是否已被释放,然后编写一个检查该标志的终结器。如果终结器检测到对象没有被释放,那么您可以让终结器通过故障快速终止进程。也就是说,如此严厉地惩罚那些忽视处置对象的用户,以至于他们被迫修复他们的错误或停止使用您的对象。

这对我来说并不好、好或礼貌,但你是唯一一个知道不处置该物品的可怕、可怕后果的人。对不遵守你疯狂规则的人进行惩罚是否比忍受他们不遵守规则的后果更好,由你决定。

于 2010-04-20T15:03:33.340 回答
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);
            }
        }
    }
于 2010-04-20T15:04:31.737 回答
17

您可以使用 Roslyn 框架编写自己的警告/错误。您DiagnosticAnalyzer将检查所有构造函数调用以查看您的类是否正在构造以及您是否在using语句中。

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

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

请注意,理论上这也可以由第三方分析器库(例如 FxCop)来完成,但是有许多IDisposable实现不需要严格地处理,例如MemoryStream,它们Dispose并没有做很多事情,所以这些规则要么有一些白名单机制,要么报告误报。

于 2016-05-23T11:25:04.100 回答
5

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

于 2010-04-20T13:42:44.893 回答
5

using 语句是编译器从中转换的简写:

(using DisposableObject d = new DisposableObject()){}

进入:

DisposableObject d = new DisposableObject()
try
{

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

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

于 2010-04-20T13:44:38.823 回答
1

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

于 2010-04-20T13:41:04.117 回答
1

不,这是不可能的。现在你可以做的是在类的终结器中调用 dispose 方法(如果他们确实调用了 dispose 方法,你可以禁止使用它)。这样,如果没有在代码中明确完成,它将触发。

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

http://www.devx.com/dotnet/Article/33167

于 2010-04-20T13:41:07.223 回答
0

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

于 2010-04-20T13:41:58.693 回答
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

于 2010-04-20T16:42:04.290 回答
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。

于 2011-06-10T03:57:15.463 回答