在 using 块的中间返回

发布于 2024-07-15 20:41:00 字数 164 浏览 5 评论 0原文

比如:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

我认为这不是返回语句的合适位置,是吗?

Something like:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

I believe it is not a proper place for a return statement, is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

分开我的手 2024-07-22 20:41:00

正如其他几位人士普遍指出的那样,这不是问题。

唯一会导致问题的情况是,如果您在 using 语句中间返回并另外返回 in using 变量。 但话又说回来,即使您没有返回并且只是保留对变量的引用,这也会给您带来问题。

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

同样糟糕

Something y;
using ( var x = new Something() ) {
  y = x;
}

As several others have pointed out in general this is not a problem.

The only case it will cause you issues is if you return in the middle of a using statement and additionally return the in using variable. But then again, this would also cause you issues even if you didn't return and simply kept a reference to a variable.

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

Just as bad

Something y;
using ( var x = new Something() ) {
  y = x;
}
狼性发作 2024-07-22 20:41:00

完全没问题。

您显然认为它

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

被盲目地翻译成:

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

不可否认,这将是一个问题,并且会使 using 语句变得毫无意义 --- 这就是为什么这不是确实如此。

编译器确保在控制离开块之前处理对象——无论它如何离开块。

It's perfectly fine.

You are apparently thinking that

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

is blindly translated into:

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

Which, admittedly, would be a problem, and would make the using statement rather pointless --- which is why that's not what it does.

The compiler makes sure that the object is disposed before control leaves the block -- regardless of how it leaves the block.

彩扇题诗 2024-07-22 20:41:00

绝对没问题——完全没问题。 为什么你相信这是错误的?

using 语句只是 try/finally 块的语法糖,正如 Grzenio 所说,从 try 块返回也可以。

将计算返回表达式,然后执行finally 块,然后该方法将返回。

It's absolutely fine - no problem at all. Why do you believe it's wrong?

A using statement is just syntactic sugar for a try/finally block, and as Grzenio says it's fine to return from a try block too.

The return expression will be evaluated, then the finally block will be executed, then the method will return.

ㄟ。诗瑗 2024-07-22 20:41:00

这将完全正常工作,就像在 try{}finally{} 中间返回一样

This will work perfectly fine, just as returning in the middle of try{}finally{}

吃→可爱长大的 2024-07-22 20:41:00

这是完全可以接受的。 using 语句确保 IDisposable 对象无论如何都会被释放。

来自 MSDN

using 语句可确保即使在调用对象方法时发生异常,也会调用 Dispose。 您可以通过将对象放入 try 块中,然后在 finally 块中调用 Dispose 来实现相同的结果; 事实上,这就是编译器翻译 using 语句的方式。

That is totally acceptable. A using statement ensures the IDisposable object will be disposed no matter what.

From MSDN:

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler.

千纸鹤 2024-07-22 20:41:00

下面的代码显示了 using 的工作原理:

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

输出:

“t1”已创建。
“t2”已创建。
“t3”已创建。
创建“从 t1、t2、t3 创建”。
“t3”已被处置。
“t2”已被处置。
“t1”已被处置。

释放函数在 return 语句之后、函数退出之前被调用。

The code bellow shows how using is working:

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

Output:

't1' is created.
't2' is created.
't3' is created.
'Created from t1, t2, t3' is created.
't3' is disposed.
't2' is disposed.
't1' is disposed.

The disposed are called after the return statement but before the exit of the function.

沐歌 2024-07-22 20:41:00

也许这并不是 100% 正确,这是可以接受的......

如果您碰巧嵌套使用并从嵌套使用中返回,则可能不安全。

以此为例:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

我传入一个 DataTable 以将其输出为 csv。 当 return 位于中间时,它将所有行写入流,但输出的 csv 总是缺少一行(或多行,具体取决于缓冲区的大小)。 这告诉我有些东西没有正确关闭。

正确的方法是确保之前的所有使用都得到正确处理:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}

Perhaps it isn't 100% true that this is acceptable...

If you happen to be nesting usings and returning from within a nested one, it might not be safe.

Take this as an example:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

I was passing in a DataTable to be outputted as csv. With the return in the middle, it was writing all the rows to the stream, but the outputted csv was always missing a row (or multiple, depending on the size of the buffer). This told me that something wasn't being closed properly.

The correct way is to make sure all the previous usings are disposed properly:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文