【问题标题】:CLR: If a constructor fails will it always throw an exception?CLR:如果构造函数失败,它总是会抛出异常吗?
【发布时间】:2009-06-28 12:31:23
【问题描述】:

在Delphi中,如果在构建对象的过程中出现异常:任何分配的内存都会被释放并抛出异常。例如,保证返回一个有效的Camera对象,或者抛出一个异常:

Camera c = new Camera();

从不必须检查结果变量是否为空:

Camera c = new Camera();
if (c == null)
   throw new Exception("Error constructing Camera") //waste of time

在 CLR 中也是如此吗?

还有其他语法结构可以保证返回值有效或抛出异常吗?

  • 创建结构(例如矩形)?
  • 获取枚举成员?
  • Object.ToString() 的结果?
  • 数学运算?

在进行数学运算的情况下:

Int32 aspect = 1650.0 / 1080.0;
if (aspect == null) 
   throw new Exception("Division of two numbers returned null")

【问题讨论】:

    标签: .net clr defensive-programming


    【解决方案1】:

    .Net 中的构造函数保证返回对象类型的非空实例。实例是否有效取决于类型的各个语义。

    构造函数中抛出的异常不会被 CLR 任意吞下(尽管用户代码可以吞下它们)。 CLR 将像在任何其他方法中引发的异常一样传播异常,并且最终将正确地对对象进行垃圾收集。

    至于你提到的其他情况

    • 创建结构:根据定义,结构永远不能为空。构造函数中抛出的异常会正常传播
    • 获取枚举成员:枚举是底层的结构/值类型,也永远不会为空
    • Object.ToString() 的结果:这可以(很遗憾地)为空。 String 是一种引用类型,从 ToString 覆盖返回 null 是完全合法的(请不要)。
    • 数学运算:这在很大程度上取决于项目的溢出设置和所使用的特定类型(整数与浮点)。

    这个数学问题几乎值得自己回答。一方面,对原始类型进行数学运算的结果永远不会为空。但它仍然可能无效。例如,以下代码不会抛出,但结果是否有效在很大程度上取决于您的具体场景

    float f1 = 1.0;
    float f2 = f1 / 0;
    

    此时 f2 是一个非常具体的浮点值,不代表实数。它有效吗?取决于您的用例。

    【讨论】:

      【解决方案2】:

      是的。我想这样说(因为 fail 也可能意味着 logical failure):如果构造函数没有抛出异常,则返回值保证为non-null 所以你永远不必执行这样的检查。

      创建结构(例如矩形):struct 根本不能是nullNullable 类型被认为是完全不同的类型,即typeof(int?) != typeof(int))。调用结构的构造函数要么会因抛出异常而失败,要么会返回一个实例。

      获取枚举成员:enum 只是一组常量。没有什么能比得上“在运行时获取成员”。它在编译时被替换。

      Object.ToString() 的结果:与任何方法一样,它可以返回 string 类型的任何有效值,包括 null,并且还可以抛出异常(在这种情况下,它根本不返回值)。

      数学运算:所有表达式都会返回值或抛出异常。返回值可以是该类型的任何有效值(例如,Int32 永远不能是 null)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-07
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 2012-01-21
        • 2014-11-03
        相关资源
        最近更新 更多