好奇的C#使用语句扩展

Mat*_*hew 26 c# using finally try-catch expansion

我跑ildasm发现这个:

    using(Simple simp = new Simple())
    {
        Console.WriteLine("here");
    }
Run Code Online (Sandbox Code Playgroud)

生成与此等效的IL代码:

    Simple simp = new Simple();
    try
    {
        Console.WriteLine("here");
    }
    finally
    {
        if(simp != null)
        {
            simp.Dispose();
        }
    }
Run Code Online (Sandbox Code Playgroud)

而问题是为什么它会在最后检查null?只有在执行try块时才会执行finally块,并且只有在Simple构造函数成功时才会执行try块(即不抛出异常),在这种情况下simp将为非null.(如果担心在Simple构造函数和try块的开头之间可能会出现一些干预步骤,那么这确实是一个问题,因为可能会抛出一个异常,阻止finally块执行.)那么,为什么地狱?

暂且不谈(请)使用声明是否比try-finally更好的论点,我将try-finally块写成:

    Simple simp = new Simple();
    try
    {
        Console.WriteLine("here");
    }
    finally
    {
        simp.Dispose();
        simp = null;        // sanity-check in case I touch simp again
                            // because I don't rely on all classes
                            // necessarily throwing
                            // ObjectDisposedException
    }
Run Code Online (Sandbox Code Playgroud)

n8w*_*wrl 22

不,最终块将始终执行.您可能无法从新的对象获取对象,而是从返回对象的其他函数获取对象 - 它可能返回NULL.使用()是你的朋友!

dss539非常友好地建议我加入他的笔记:

using(Simple simp = null) 
Run Code Online (Sandbox Code Playgroud)

扩展必须首先检查为空的另一个原因.

  • 假设'new'会在失败时抛出异常,因此永远不会返回Null.如果它抛出异常,则甚至不会到达try块,并且finally块不会被执行.因此,finally块不会一直执行. (11认同)
  • 如果构造函数失败(在try之前),则finally将不会执行. (10认同)
  • 只是为了扩展一点,您可以使用Factory Pattern并执行类似使用(myFactory.CreateMyObject())的操作,这可能会导致null对象. (2认同)
  • @ n8 - 您应该将我的答案编辑到您的答案中,以便OP可以接受您的答案作为完整答案. (2认同)

dss*_*539 11

using(Simple simp = null)又是另一种的扩张必须先检查空的原因.

  • 如果您使用simp对象,它只能保证是运行时错误.如果不这样做,就没有理由使用.... (2认同)
  • using(Simple simp = null){if(someCondition)simp = new Simple(1); else if(otherCondition)simp = new Simple(2); ......}无论如何都会处理simp. (2认同)
  • @configurator - 是的,但这仍然有点......危险.simp = new Simple(); 然后是另一个simp = new Simple(); 它只会处置其中一个 (2认同)
  • ...并且它没有编译:错误CS1656:无法分配给'simp',因为它是'使用变量' (2认同)