【问题标题】:Why does this code not throw an exception?为什么这段代码不抛出异常?
【发布时间】:2014-01-20 03:13:52
【问题描述】:

我预计以下代码行会引发异常,因为我正在访问一个赋值为null 的可为空变量的Value 属性。但是,当我执行以下操作时,我没有得到任何异常:

int? x=null;
Console.WriteLine(x.Value==null);

但是当我这样做时:

Console.WriteLine(x.Value);

不出所料,我确实遇到了异常。

但是这两种访问x.Value的方式有什么区别呢?为什么在第一种情况下我没有得到异常?这两段代码毕竟都在尝试访问 x.Value 属性。

注意:我在www.compileonline.com 网站上运行上述代码,顺便说一句。不确定尝试使用 Visual Studio 编译器是否会产生不同的结果,但我目前无法访问 Visual Studio。

TIA。

【问题讨论】:

  • 控制台.WriteLine(x.Value==null);也会抛出 Invalid operationexception。
  • 两者都抛出异常。
  • compileonline.com 使用 Mono 编译器,而不是 Microsoft 的。我想你可能在那个编译器中发现了一个错误。
  • 看来您在在线编译器中发现了一个错误。
  • 我得到:警告为错误:表达式的结果始终为“假”,因为“int”类型的值永远不等于“int”类型的“null”?所以也许它是一种优化。

标签: c# exception


【解决方案1】:

当使用您指出的website compile online 时,单声道编译会重写/优化您的代码:

using System.IO;
using System;

class Program
{
    static void Main()
    {
        int? x=null;
        Console.WriteLine(x.Value==null);  //-> Console.WriteLine(false);    
    }
}

正在编译源代码....

$mcs main.cs -out:demo.exe 2>&1

main.cs(9,38): 警告 CS0472: 比较值类型的结果int' with null isfalse'

编译成功 - 1 个警告

执行程序....

$mono demo.exe

错误

警告 CS0472 告诉你,这是他们正在使用的在线/单声道编译器中的一个错误。

【讨论】:

  • -1 因为警告没有告诉您x.Value 没有被评估,警告只告诉您与null 的比较将永远不会返回true
  • 如果代码没有被编译器重写,它会在运行时失败并出现异常,但它不会在运行时失败。使用的mono编译器有bug,微软编译器会给你不同的结果。
  • 警告说代码检索x.Value,丢弃它,并打印false。实际行为是打印false而没有检索x.Value。所以,不,警告仍然没有告诉你。
  • @peer:感谢您指出有关单声道编译器重写的事实。编译器在对代码进行优化重写之前不检查代码中可能存在的异常似乎是错误的行为。
【解决方案2】:

两个代码都抛出 InvalidOperationException 因为

来自Nullable<T>.Value property

如果HasValue 属性,则为当前Nullable<T> 对象的值 是true如果 HasValue 属性为 false,则会引发异常

在这两种情况下,HasValue 属性将为 false。这就是为什么两个代码都会抛出InvalidOperationException

编辑:Okey okey.. 看起来 www.compileonline.com 网站使用 Mono 2.10.2.0,第一个代码只给出警告;

main.cs(9,34): 警告 CS0472: 比较值类型的结果 int' with null isfalse'

我查看了Bug Fixes 页面,但我找不到有关此问题的任何信息。继续搜索。。

看起来像 Mono 2.10.2.0 即使HasValue 为假,此代码也不会抛出异常。它只是给出警告。

来自Compiler Warning (level 2) CS0472

表达式的结果总是'value1',因为一个类型的值 “value2”永远不等于“value3”类型的“null”

所以在我们的例子中,看起来像 Mono 2.10.2.0 检查 xint?x.Valueint 并且它说像(而不是抛出异常);

这是一个int,它是一个值类型,它永远不会等于null

EDIT2:我认为hdv 有一点。这似乎与在 Mono 3.1.10 中修复的 Bug 12608 有关,但我不能确定。

继续寻找..

EDIT3:好的.. 我在Ideone 上尝试了这些代码,在sample page 它说它使用Mono 2.8 进行C# 编译器,结果是令人惊讶..

你的first example

int? x = null;
Console.WriteLine(x.Value == null);

它不会抛出任何异常,它甚至也不会显示任何警告。它完美地工作并因此生成False。看起来它没有检查 HasValue 属性,甚至看起来 Nullable<T> 的根(在我们的例子中是 int)是否是 值类型

你的second example

int? x = null;
Console.WriteLine(x.Value);

按照我们的预期抛出InvalidOperationException

未处理的异常:System.InvalidOperationException:可空对象 必须有一个值。在 System.Nullable`1[System.Int32].get_Value () [0x00000] in :0 at Test.Main () [0x00000] in :0

等一下..

first example,我们说;

看起来它没有检查 HasValue 属性..

这次它怎么可能检查HasValue 属性?我认为这是一个在线编译器错误,但我仍然无法在 Mono 3.+ 版本上检查它..

EDIT4:我通过 contact page 向创建此站点的人发送了一条消息,并解释了这种情况。

【讨论】:

  • 问题说第一个代码没有抛出异常,问为什么。这个问题的答案如何?
  • 这可能是 bug 12608 的不同表现形式,在 Mono 3.1.1 中已修复(根据其发行说明)。不过,我没有在这里安装 Mono 来检查。
  • @hvd Hmm,是的,这可能与这个错误有关。我也没有 Mono 这就是为什么我无法检查它。添加了我的答案。谢谢。
  • @Barmar 现在怎么样?
【解决方案3】:

您使用的编译器错误地优化了对属性get 访问器的调用。此代码使用该编译器重现了该错误:

using System;

static class Program
{
    static void Main()
    {
        Console.WriteLine(Prop == null);
    }

    static int Prop
    { 
        get
        {
            throw new NotImplementedException("This error must be!"); 
        } 
    }
}

Visual C# 编译器没有这个错误。但在某些情况下,它的警告文本很糟糕。尝试在我的代码中将int 更改为DateTime,并将== 更改为>,然后查看来自Visual C# 编译器的警告文本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 2013-11-13
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    相关资源
    最近更新 更多