为啥短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException?

Posted

技术标签:

【中文标题】为啥短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException?【英文标题】:Why does short-circuiting not prevent MissingMethodException related to unreachable branch of logical AND (&&)?为什么短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException? 【发布时间】:2011-07-11 03:04:58 【问题描述】:

在检查我的 windows mobile 单元上是否存在并启用了摄像头时,我遇到了一些我不明白的事情。

代码如下:

    public static bool CameraP()

        return Microsoft.WindowsMobile.Status.SystemState.CameraPresent;
    

    public static bool CameraE()
    
        return Microsoft.WindowsMobile.Status.SystemState.CameraEnabled;
    

    public static bool CameraPresent1()
    
        return Microsoft.WindowsMobile.Status.SystemState.CameraPresent
              && Microsoft.WindowsMobile.Status.SystemState.CameraEnabled;
    

    public static bool CameraPresent2()
    
        return CameraP() && CameraE();
    

当我调用 CameraPresent2() 时,它返回 false(没有摄像头)。但是当我打电话给CameraPresent1() 时,我收到一个 MissingMethodException 并带有注释“找不到方法:get_CameraEnabled Microsoft.WindowsMo​​bile.Status.SystemState。”

CameraPresent1 中评估第二个术语是否仅仅因为它们都是属性(在语言级别)?

还有什么可以解释行为差异的吗?

【问题讨论】:

如果你调用 CameraE() 你会得到同样的异常吗? “短路”在这里会比“懒惰”更好...... 让我感到困惑的部分是我在 msdn 中根本找不到对 CameraEnabled 的引用......不过我打算去“一些自定义的 && 重载”。 @The_Butcher 是的,如果我调用 CameraE() 会引发相同的异常。 @Massif:那里也找不到,但是当我从 VS2008 浏览 Microsoft.WindowsMo​​bile.Status 时可以找到它。它适用于具有摄像头的其他单元。这给了我一些新的想法。 【参考方案1】:

不计算第二项。

不评估第一项。

CameraPresent1() 方法甚至没有开始执行。

当您第一次调用CameraPresent1() 时,运行时必须将 MSIL 即时编译为本机代码。这需要解决所有的方法调用,即使是那些只能有条件地到达的方法调用。 MissingMethodException 编译失败。

使用CameraPresent2(),只有在第一次调用CameraE() 时才会编译对CameraEnabled 的getter 的调用,这永远不会发生。

【讨论】:

很好的答案——实际上回答了这个问题 谢谢!这给了我一些深刻的见解,不仅对我的问题,而且对 JIT 编译器的工作方式和时间。 回答弗里茨的评论,由于低代表被放置在答案中,并且由于单词选择不佳被mod删除 - 属性的执行速度不比方法快。属性不过是一对方法的语法糖,getter 和 setter。 (语法糖意味着编译器将其转换为相同的输出可执行文件)【参考方案2】:

C# Specification 7.12 节

&&|| 运算符称为条件逻辑运算符。它们也被称为“短路”逻辑运算符。

&&|| 运算符是 & 和 | 的条件版本运营商:

操作x && y对应于操作x & y,除了y只有在x不是false时才会被评估。

操作x || y对应于操作x | y,除了y仅在x不是true时才被评估。


也就是说,C# 规范保证CameraE() 将被调用当且仅当 CameraP() 为真。

这可能是过度编译器优化的问题,因此实际程序似乎违反了语言规范...


编辑:

是否可以设置断点并显示反汇编窗口,以查看生成的确切代码?

【讨论】:

我认为他在问为什么在调用 CameraPresent1 时看起来 && 似乎是懒惰的。 @Marc:我……不知道……我以为那只是为了玩弄……哦,天哪,我不擅长这个…… RB 是正确的。 && 运算符怎么会像没有短路一样工作。我将编辑问题标题。 “短路”是什么意思? @John Gietzen:但是CameraPresent1() 呢?显然,第二个参数被评估。这是我应该将其视为 VS2008 实现中的错误吗?【参考方案3】:

只是一个疯狂的猜测,但这有可能是 JIT 编译问题吗?调用 CameraPresent1 时,是否尝试将调用 Microsoft.WindowsMo​​bile.Status.SystemState.CameraEnabled 映射到底层设备?由于找不到方法 get_CameraEnabled,因此整个函数失败并出现 MissingMethodException。

【讨论】:

我只是想重现问题,但无法编译,因为找不到 CameraEnabled。该应用程序是否为您编译?您有哪些项目参考资料? @Justin Largey:Microsoft.WindowsMo​​bile.Status 的运行时版本是 v1.1.4322。 有趣,这和我的版本一模一样。我似乎无法在任何地方找到 CameraEnabled。在您的代码中,您可以尝试选择 CameraEnabled 属性,然后按 F12(转到定义)。 VS 真的带你去定义这个属性吗?项目是否有可能引用了一个针对 MS.WindowsMo​​bile.Status 命名空间进行扩充的程序集?或者VS中的运行时和手机上的运行时不匹配。 (即 VS 中的运行时认为有一个 CameraEnabled 属性,但手机上的实际运行时没有它。) 我可以从我的代码导航到定义。您使用的是什么目标平台?我目前只安装了 Windows Mobile 6 SDK,所以我无法仔细检查它是否也适用于 WM5。但由于它只在带有 WM5 的设备上失败,我想这可能是错误发生的地方。 我认为你是对的。我有 Windows Mobile 5 SDK,它没有 CameraEnabled 属性。但是,我猜 v6 SDK 确实有这个属性。这也解释了为什么它适用于 WM6,但不适用于 WM5。【参考方案4】:

查看报告的问题,似乎没有任何意义。这两个版本应该是相同的。不过,我想知道这里的问题是否是相机 API 在某些时候使用了 dynamic,并且它正在尝试寻找 true()/false()/& 运算符。这可能会说服它切换到bool 逻辑:

public static bool CameraPresent1()

    return ((bool)Microsoft.WindowsMobile.Status.SystemState.CameraPresent)
          && ((bool)Microsoft.WindowsMobile.Status.SystemState.CameraEnabled);

【讨论】:

仍然不会输入CameraPresent1()。我更倾向于 Ben Voigt 的回答。

以上是关于为啥短路不能防止与逻辑 AND (&&) 的不可达分支相关的 MissingMethodException?的主要内容,如果未能解决你的问题,请参考以下文章

Java 逻辑运算符短路

&&(短路与)&|||(短路或)

逻辑运算符短路与,短路或

25短路逻辑运算符

25短路逻辑运算符

短路运算符(逻辑与&& 和 逻辑或||)