什么是可识别的替代用途

本文关键字:识别 什么 | 更新日期: 2023-09-27 17:57:24

System.IDisposable 接口的 msdn 文档指出

此接口的主要用途是释放非托管资源。

我想知道什么是替代用途。

例如,我们还需要 IDisposable 接口用于其他已分配的资源,例如事件订阅等。

我们使用接口作为标记,以允许类实例知道何时不再从客户端使用它。客户端和基础结构代码在不再需要实现代码的类的逻辑实例时显式调用 IDisposable.Dispose()。与从接口包装的非托管资源没有任何关系。

当我们为这种行为选择IDisposable接口时,我们认为它是接口的替代(未记录)使用。

您发现IDisposable的替代用途是什么?它们合法吗?MSDN 文档有误吗?

什么是可识别的替代用途

我认为您对文档的阅读是错误的。说任何与非托管资源无关的IDisposable用法都是无记录的,有点像说任何不计算事物的System.Int32用法都是无记录的。它是一个接口,没有实现,甚至没有功能可以开始区分记录的内容和未记录的内容。

IDisposable的目的只是为开发人员提供一种机制来确定性地控制其对象的生存期。碰巧的是,这主要是处理非托管资源的要求。

IDisposable的一个更花哨的用途是using块句法糖。正如其他人所提到的,using块给出了一个操作范围,我认为这些非常优雅。

示例 1 - 定时块

StackOverflow使用迷你分析器,该分析器使用using块来识别嵌套的执行区域:

using (profiler.Step("Doing complex stuff"))
{
    using (profiler.Step("Step A"))
    { // something more interesting here
        Thread.Sleep(100);
    }
    using (profiler.Step("Step B"))
    { // and here
        Thread.Sleep(250);
    }
}

不使用using的替代方案非常可怕,我什至不想在这里模拟它。

示例 2 - 一次性操作

在 .NET 域驱动设计圈中,一次性操作模式制作轮次有不同的变体。Ayende有一个,Udi Dahan在他的Domain Events实现中也是如此,Jimmmy Bogard对此的看法略有不同,仍然在Domain Events的背景下。该模式的关键是您希望在某些上下文中执行某些操作,然后在完成后将上下文恢复到以前的状态。

Ayende提供了一个简单的例子:

class UsuallyReadOnly { 
  //.. implementation
  public IDisposable AllowModification
  {
    get 
    {
        _allowModification = true;
        return new DisposableAction(()=>{ _allowModification = false; } );
     }
  }
}

UsuallyReadOnly的用法:

UsuallyReadOnly foo = new UsuallyReadOnly();
using(foo.AllowModification)
{
  foo.Name = "Bar";
}
IDisposable通常

与用于在一定范围内激活和停用某些内容结合使用,即使它不是非托管资源。您描述声音作为参考计数的用途,当然不建议使用。

对于"资源",请替换"责任"。 当一个对象被认为拥有非托管资源时,这实际上意味着有一些任务需要在某个时候完成,而该对象是唯一具有完成该任务所需的信息和动力的东西。 "处置"的目的不是摆脱任何有形实体,而是允许对象"整理其事务"。 有人在死前整理好自己的事务,并不是在对自己做任何事情,而是在确保他必须对自己以外的人和事做的事情得到完成。 IDisposable.Dispose也是如此。

请记住,还有一种使用模式,它的作用有点像 RAII

using ( DisposableObject obj = new DisposableObject( ) )
{
    .....
}

因此,当 using 块退出时,Dispose 会被调用。

IDisposable接口更流行的用途之一是事务范围。您可以使用它将一些 SQL 逻辑包装在事务中,并显式调用 Complete() 来结束事务:

using (var scope = new TransactionScope())
{
    using (var connection = new SqlConnection(connectString))
    {
        // perform sql logic
        ...
        scope.Complete(); 
    }
}

您还可以将类似的模式用于需要临时函数的任何内容,例如创建和删除临时文件:

public class TempFileProvider : IDisposable
{
    public Filename { get; private set; }
    public TempFileProvider()
    {
        Filename = Path.GetTempFileName();
    }
    public void Dispose()
    {   
        File.Delete(Filename);
    }
}

所以你可以像这样使用它:

using (var tempFileProvider = new TempFileProvider())
{
    DoSomethingWithFile(tempFileProvider.Filename);
} // deletes temp file

看看下面的问题 需要我的 IDisposable Hack 的替代品

在那里,我举了一个很好的例子来说明我使用IDisposable的目的。 :)

当然,这不是理想的解决方案,但是,它对我有很大帮助。