ChatGPT解决这个技术问题 Extra ChatGPT

使用 {} 语句在内部调用 return 是一种好方法吗?

我只想知道在 using 块内调用 return 是否安全/好方法。

例如。

using(var scope = new TransactionScope())
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}

我们知道最后一个大括号 dispose() 将被取消。但是在上述情况下会发生什么,因为 return 将控件跳出给定范围(AFAIK)......

我的 scope.Complete() 被调用了吗?对于作用域的 dispose() 方法也是如此。

一旦 using{} 范围结束,相关对象将被释放,return 将“破坏”范围 - 因此对象将按预期释放
请注意,您提供的示例永远不会命中您的 scope.Complete() 调用,因此您的事务将始终回滚。
无论是否调用了 usingdispose(),当您返回时,包含此 using 块的函数都将返回,并且属于它的所有内容都将成为孤立的。因此,即使 scope 没有被“using”处置(正如其他人所解释的那样),它也会因为函数结束而被处置。如果 C# 有 goto 语句 - 你笑完了吗?好 - 那么你可以 goto 在右大括号之后而不是返回,而不是返回。从逻辑上讲,scope 仍会被释放,但您只是将 goto 放入 C# 中,所以在那个阶段谁在乎逻辑。
C# has goto

Ø
Øyvind Bråthen

using 块内调用 return 是非常安全的,因为 using 块只是一个 try/finally 块。

在上面的示例中,在返回 true 之后,范围将被释放并返回值。 return false,而 scope.Complete()不会被调用。但是,Dispose 将被调用,因为它位于 finally 块中。

您的代码与此基本相同(如果这样更容易理解):

var scope = new TransactionScope())
try
{
  // my core logic
  return true; // if condition met else
  return false;
  scope.Complete();
}
finally
{
  if( scope != null) 
    ((IDisposable)scope).Dispose();
}

请注意,您的事务将从不提交,因为无法到达 scope.Complete() 提交事务。


您应该明确说明Dispose 被调用。如果 OP 不知道 using 中发生了什么,他很可能不知道 finally 中发生了什么。
可以将 using 块保留为 return,但在 TransactionScope 的情况下,您可能会遇到 using 语句本身的问题:blogs.msdn.com/b/florinlazar/archive/2008/05/05/8459994.aspx
根据我的经验,这不适用于 SQL Server CLR 程序集。当我需要为包含引用 MemoryStream 对象的 SqlXml 字段的 UDF 返回结果时。我得到“无法访问已处理的对象”和“当流关闭时调用读取的尝试无效。”,所以我被迫编写泄漏代码并在这种情况下放弃使用语句。 :( 我唯一的希望是 SQL CLR 将处理这些对象的处置。这是一个独特的场景,但我想我会分享。
@MikeTeeVee - 更清洁的解决方案是(a)让调用者执行 using,例如 using (var callersVar = MyFunc(..)) ..而不是在“MyFunc”内部使用 - 我的意思是调用者被赋予流和负责通过 using 或显式关闭它,或者 (b) 让 MyFunc extract 任何需要的信息到其他对象中,可以安全地传回 - 然后可以将底层数据对象或流由您的 using 处置。您不必编写泄漏代码。
L
Lucero

这很好 - finally 子句(这是 using 子句的右花括号在幕后所做的)总是在离开范围时执行,无论如何。

但是,这只适用于 finally 块中的语句(使用 using 时无法显式设置)。因此,在您的示例中,scope.Complete() 永远不会被调用(但我希望编译器会警告您有关无法访问的代码)。


M
M. Mennan Kara

一般来说,这是一个很好的方法。但在您的情况下,如果您在调用 scope.Complete() 之前返回,它只会丢弃 TransactionScope。取决于你的设计。

因此,在这个示例中,Complete() 没有被调用,并且作用域被释放,假设它继承了 IDisposable 接口。


它必须实现 IDisposable 或使用不会编译。
T
Tony Kh

scope.Complete 绝对应该在 return 之前调用。编译器将显示警告,并且永远不会调用此代码。

关于 return 本身 - 是的,在 using 语句中调用它是安全的。 using被翻译成try-finally块在幕后,finally块肯定会被执行。


d
daryal

在您提供的示例中,存在问题; scope.Complete() 永远不会被调用。其次,在 using 语句中使用 return 语句不是一个好习惯。请参阅以下内容:

using(var scope = new TransactionScope())
{
    //have some logic here
    return scope;      
}

在这个简单的例子中,重点是;当 using 语句完成时,scope 的值将为空。

所以最好不要在 using 语句中返回。


仅仅因为“返回范围”没有意义,并不意味着返回语句是错误的。
仅仅因为不使用最佳实践并不意味着您做错了什么。这意味着,最好避免,因为它可能会导致无法预料的后果。
scope 的值不会为 null - 唯一会发生的事情是 Dispose() 将在该实例上被调用,因此该实例 不应 不再使用(但它is not null 并且没有什么可以阻止您尝试使用已处置的对象,即使这确实是对一次性对象的不当使用)。
卢塞罗是完全正确的。可处置对象在处置后不为空。它的 IsDisposed 属性为 true,但如果您检查 null,则会得到 false,并且 return scope 返回对 that 对象的引用。这样,如果您在返回时分配该引用,则会阻止 GC 清理已处置的对象。
T
ThunderGr

在这个例子中,scope.Complete() 永远不会执行。但是,return 命令将清除堆栈上分配的所有内容。 GC 将处理所有未引用的内容。所以,除非有不能被 GC 拾取的对象,否则没有问题。