【问题标题】:Does using statement keep a reference to object(s) it receive?using 语句是否保留对它接收到的对象的引用?
【发布时间】:2019-06-04 15:32:23
【问题描述】:

当像这样使用“使用”语句时:

  using (Global.Instance.BusyLifeTrackerStack.GetNewLifeTracker())
  {
    ...

而不是

  using (var lt = Global.Instance.BusyLifeTrackerStack.GetNewLifeTracker())
  {
    ...

“using”语句是否会保留对返回对象的引用,以确保不会过早地对其进行垃圾收集?...如果没有为它声明显式变量(第一个示例代码)?

第二个示例代码显然没问题,但第一个示例代码???

任何文档和/或信息参考将不胜感激。

【问题讨论】:

  • 可以,否则无法调用Dispose
  • 是的,引用lt仅供您在块中使用。如果你不需要使用它,你不需要声明它。 using 块将以任何一种方式处理对象。这是您偶尔会看到的一种模式,其中创建对象只是为了在其 Dispose() 方法中撤消的临时副作用。例如,我们有一个名为 WaitCursor 的类,它在构造函数中将光标设置为等待光标,并在 Dispose() 中将其恢复为之前的状态。
  • 是的,一个真正的参考。正如 Ed 建议的那样,这种模式通常用于在处置中做一些有副作用的事情。例如在 Razor 中,using(Html.BeginForm){...} 允许处理返回的对象以在末尾输出 </form> 标记。
  • documentation for using 说了很多,当然还有the C# standard
  • 我刚刚验证过。我打电话给:使用 (Global.Instance.BusyLifeTrackerStack.GetNewLifeTracker()) { GC.Collect(); GC.WaitForPendingFinalizers();并调用了“Dispose”。非常感谢...是的,我知道,我应该在问我的问题之前进行验证...对不起!

标签: c# reference garbage-collection using idisposable


【解决方案1】:

是的,保留了一个真实的引用,以便最后可以调用Dispose 方法。当您不需要显式访问 using 块内的一次性对象时,此模式通常用于在处置中执行某种“副作用”。例如,在 Razor 中,using(Html.BeginForm){...} 允许对返回的对象进行处置以在末尾输出 </form> 标记。

C# 中的一个简单示例是:

public class MessageGenerator : IDisposable
{
    public MessageGenerator()
    {
        Console.WriteLine("To whom it may concern,");
    }
    
    public void Dispose()
    {
        Console.WriteLine("Thanks and goodbye.");
    }
}

还有这样的用法:

using (new MessageGenerator())
{
    Console.WriteLine("Please give me lots of reputation.");
}

会给出这样的输出:

它可能与谁有关,

请给我很多声望

谢谢,再见。

【讨论】:

  • 感谢 DavidG,我最终决定选择 Heretic Monkey,因为我得到了解释该行为的确切文档。另外,我认为您需要强制垃圾收集器收集到“使用”语句块中以证明行为。但是非常感谢。我感觉好多了,因为我确实在我的代码中经常使用该模式而不分配任何变量(使用“使用”)。
  • 不,这不是关于 GC,而是关于调用 Disposeusing 语句实际上只是围绕 try/finally 块的语法糖。 GC 稍后会在未指定的时间发生。
  • 我担心我的一次性对象在到达 finally 块和 Dispose 方法之前可能已经被垃圾回收了。这就是为什么在我看来,强制 GC 收集是确保正确行为的必要条件。样本或文档都可以证明这一点。异端找到了适当的文档。
  • 不,完全不需要强制 GC。
【解决方案2】:

要回答您问题的文档和参考部分:

documentation for the using statement 备注:

using 语句以正确的方式调用对象上的Dispose 方法,并且(当您如前所示使用它时)它还会导致对象本身在调用Dispose 时立即超出范围。在using 块内,对象是只读的,不能修改或重新分配。

就第一个代码块的语法而言,C# standard 的语法如下:

using_statement
    : 'using' '(' resource_acquisition ')' embedded_statement
    ;

resource_acquisition
    : local_variable_declaration
    | expression
    ;

在那里,您会注意到resource_acquisition 可以是局部变量声明或表达式,这是您的第一个代码块使用的。

【讨论】:

  • 您得到了我正在寻找的确切文档。一个强制 GB 在 using 块内收集的示例也是一个很好的答案。谢谢!
【解决方案3】:

这是编译器在幕后所做的an example。代码如下:

using (File.OpenRead("Test.txt")){}

...转换为:

FileStream fileStream = File.OpenRead("Test.txt");
try
{
}
finally
{
    if (fileStream != null)
    {
        ((IDisposable)fileStream).Dispose();
    }
}

声明了一个变量,它包含对所用对象的引用。

【讨论】:

  • 非常感谢您的示例(来自 SharpLab 的示例)。这是一个令人难以置信的工具,我不知道它的存在。非常感谢!!!!!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 2010-11-05
  • 2014-07-19
  • 1970-01-01
相关资源
最近更新 更多