C# 尝试使用.NET4.5.1捕获最终阻止问题

C# 尝试使用.NET4.5.1捕获最终阻止问题,c#,C#,我有一个简单的测试代码,它在.NET3.5中可以正常工作,但在使用.NET4.5.1创建的项目中,同一代码的行为完全不同 class Program { static void Main(string[] args) { try { string a = null; var x = a.Length; } catch (Exception ex) {

我有一个简单的测试代码,它在.NET3.5中可以正常工作,但在使用.NET4.5.1创建的项目中,同一代码的行为完全不同

class Program
{
    static void Main(string[] args)
    {
        try
        {
            string a = null;
            var x = a.Length;
        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            Console.WriteLine("This is the finally block.");
        }
        Console.WriteLine("You should not be here if an exception occured!");
    }
}
首先,奇怪的是在运行编译后的版本exe文件时,.NET4.5.1中完全忽略了NullReferenceException类型异常。基本上,不会引发错误,尽管在调试模式下会引发异常

其次(也是最重要的),如果错误不同于NullReferenceException,例如“索引超出范围”,那么异常实际上会按预期抛出,但“finally”块从未命中,这不是我从try-catch-finally块中预期的行为。我尝试了不同的机器,我的另外两个同事也在尝试,我们都得到了相同的结果

似乎我从未真正理解try-catch-finally块,或者.NET4.5.1以不同的方式处理异常,或者.NET4.5.1存在一些bug。我所知道的是,上面的代码在.NET3.5中可以正常工作,但在.NET4.5.1中运行时,我似乎没有得到相同的结果

有人能解释一下吗?我现在完全不知所措

编辑 基于Eric J的回答,我能够解决NullReferenceException问题。因为我问了两个问题,所以我将为第二个问题创建一个新的线程。

在发布模式下,jitter(即时编译器)能够证明
x
从未被引用,因此能够删除赋值

在调试模式下,抖动不会执行该优化

要强制抛出异常,请使用
x
(例如@Henk在注释中建议,
WriteLine(x)

编辑

Eric Lippert在评论中指出

…我和其他人一样惊讶抖动会消除一根弦 可以抛出的长度指令。这对我来说似乎是错误的


抖动优化可能过于激进。

能否添加使用x的代码。编译器可能会删除这两行,因为它们未使用。一个简单的
WriteLine(x)
就可以了。最后的
问题听起来像个bug。他们似乎不太可能如此彻底地改变关键行为。您可能应该补充说,
x
从未被引用,而Length属性访问器是一个纯方法。否则编译器无法执行优化。等等,所以编译器认为抛出异常不是副作用(很明显,我的意思是给定的代码序列演示了这一点)?要么必须有一些额外的要求(否则的话,想象后果吧!),要么这是一个bug。@MichaelPetito这意味着它是一个纯方法吗?我看到它是一个MethodImplOptions.InternalCall,可能正是出于这个原因,它可以被优化,但仍然不清楚…@xanatos如果一个方法没有任何方面,它就是纯的effects@germi好啊他的意思是
的定义纯粹是
。。。但这仍然不够。。。。一个
a.Trim()
不会有任何副作用,但会抛出。
string a = null;
var x = a.Length;