【问题标题】:Is an object constructed if an initializer throws?如果初始化器抛出,是否构造了一个对象?
【发布时间】:2011-08-07 12:49:42
【问题描述】:

我在 Jag Reeghal 的博客上阅读了 This Article,在我看来,他的建议与使用对象初始化器并不相同。然后我意识到我并不确定。

当一个对象被构造时,使用对象初始化器,并且这些初始化器之一抛出(可能是空引用异常)......对象实际上是构造的吗?这基本上就像在构造函数中抛出的异常吗?还是对象完全构造,然后初始化?

【问题讨论】:

    标签: c# exception-handling object-initializers


    【解决方案1】:

    大家要注意编译出来的IL并不总是一样的!!

    区别在于调试/发布构建配置。

    如果你不相信我,看看反射器.....

    【讨论】:

      【解决方案2】:

      首先完全构造,然后初始化。但是,如果抛出异常,您将永远不会获得对此类对象的引用,编译器会确保您的引用只能引用正确初始化的对象。它使用临时来保证这一点。

      例如,这段代码:

      var obj = new Model {
         FirstName = reader[0].ToString(),
         LastName = reader[1].ToString(),
         Age = Convert.ToInt32(reader[2].ToString())
      };
      

      被编译器重写为:

      var temp = new Model();
      temp.FirstName = reader[0].ToString();
      temp.LastName = reader[1].ToString();
      temp.Age = Convert.ToInt32(reader[2].ToString())
      var obj = temp;
      

      【讨论】:

        【解决方案3】:

        var x = new Foo { Property1 = 5}; 这样的对象初始化语句将被实现为:

        Foo temp = new Foo();
        temp.Property1 = 5;
        x = temp;
        

        如您所见,初始化器中的属性是在构造对象后设置的,但是在设置所有属性之前,变量不会设置为完全初始化的对象,所以如果抛出异常,即使捕获到异常,构造的对象也会丢失(变量将保持null 或之前的任何值)。

        【讨论】:

        • 所以虽然不同,但结果与构造函数一样。所以,我认为 Jag 的建议并不完全一样是正确的。
        • 结果大体相同。异常后内存中的内容可能有所不同。 Jag 建议 ReSharper 将初始化程序建议限制为 10 个属性,否则在一行代码中发生这么多事情时,调试起来可能太困难了。
        【解决方案4】:

        对象将被构造,但初始化不会完成。初始化只是一个编译器技巧;查看生成的 IL,无论哪种方式,您都会看到相同的结果。博客文章抱怨说很难说出异常发生在哪一行,但我个人从未遇到过这样的困难。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-10
          • 1970-01-01
          • 2017-07-20
          • 2020-07-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多