新的“using”语法与长期引用的交互

问题描述

这是一些示例代码

public sealed class HoldingClass : Idisposable
{
  private BinaryReader _binaryReaderField;

  public string GetStringFromreader(int count)
  {
    var data = _binaryReaderField.ReadBytes(count);
    // ... Process data ... //
    return newString;
  }

  public void dispose()
  {
    _binaryReaderField?.Close();
    _binaryReaderField?.dispose();
  }
}

// ... somewhere else ... //

public sealed class EntryPoint : Idisposable
{
  public static Start(string filePath)
  {
    using var br = new BinaryReader(File.OpenRead(filePath));
    return new EntryPoint { _holdingClass = new HoldingClass(br) };
  }

  private HoldingClass _holdingClass;

  public string GetString(int count)
  {
    return _holdingClass.GetStringFromreader(count);
  }

  public void dispose()
  {
    _holdingClass?.dispose();
  }
}

请注意,这是一个人为的示例,用于表达我感兴趣的行为,并不代表任何类型的生产代码

好的,所以在上面的代码中,假设应用程序以 using var ep = EntryPoint.Start("someFile.txt"); 启动,然后在发生其他处理后的方法中,开发人员然后调用 ep.GetString(155);

BinaryReader using 语句的行为是什么?

“常识”告诉我,只要您离开 EntryPoint.Start 方法的范围,对象就会被释放。稍后通过 HoldingClass 实例使用它的任何尝试都将导致 Objectdisposed 异常。 但是,我不太清楚新的 using 智能行为是如何工作的。是通过引用计数完成的吗?在这种情况下,BinaryReader 对象将在 HoldingClass 实例的整个生命周期中保持活动状态。

在 C++ 中,我会通过实例化一个唯一指针并将所有权转移给新对象来解决这个问题,但据我所知,C# 不是这样工作的。

解决方法

新的 using 语法实际上只是一种语法糖,用于减少需要使用大括号来显示对象应在其后处理的范围的“噪音”。没有关于它的“新”启发式方法。您发布的代码的等效旧样式是:

public static EntryPoint Start(string filePath)
{
    using (using var br = new BinaryReader(File.OpenRead(filePath)))
    {
        return new EntryPoint { _holdingClass = new HoldingClass(br) };
    }
}

在任何一种风格中,这是一个代码错误,并且持有类将始终包含一个已释放的引用,因为它在调用者有权访问由 EntryPoint 方法返回的 Start() 实例之前已被释放.

使用旧的或新的语法,您在这里尝试做的不是 using 的适当用法,您应该将其省略,例如:

public static EntryPoint Start(string filePath)
{
    var br = new BinaryReader(File.OpenRead(filePath));
    try
    {
        return new EntryPoint { _holdingClass = new HoldingClass(br) };
    }
    catch (Exception)
    {
        br.Dispose();
        throw;
    }
}

如果在创建结果时发生异常,则此处处理 BinaryReader,否则您需要将其控制权传递给您的 HoldingClass 实现并使其和 EntryPoint 实现IDisposable 并在处置时适当处置。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...