做短路运算符||和&功放;&安培;有可能为空的布尔值?该RuntimeBinder有时是这样认为的 [英] Do short-circuiting operators || and && exist for nullable booleans? The RuntimeBinder sometimes thinks so

查看:216
本文介绍了做短路运算符||和&功放;&安培;有可能为空的布尔值?该RuntimeBinder有时是这样认为的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读了的条件逻辑运算符 || &放了C#语言规范;&安培; ,也被称为短路逻辑运算符。对我来说,它似乎还不清楚,如果这些存在了可空布尔值,即数类型可空<布尔> (也写作布尔),所以我与非动态类型试了一下:

I read the C# Language Specification on the Conditional logical operators || and &&, also known as the short-circuiting logical operators. To me it seemed unclear if these existed for nullable booleans, i.e. the operand type Nullable<bool> (also written bool?), so I tried it with non-dynamic typing:

bool a = true;
bool? b = null;
bool? xxxx = b || a;  // compile-time error, || can't be applied to these types

这似乎解决的问题(我无法理解规范显然,但假设在Visual C#编译器的实现是正确的,现在我知道)。

That seemed to settle the question (I could not understand the specification clearly, but assuming the implementation of the Visual C# compiler was correct, now I knew).

不过,我想尝试用动态结合为好。所以我想这个代替:

However, I wanted to try with dynamic binding as well. So I tried this instead:

static class Program
{
  static dynamic A
  {
    get
    {
      Console.WriteLine("'A' evaluated");
      return true;
    }
  }
  static dynamic B
  {
    get
    {
      Console.WriteLine("'B' evaluated");
      return null;
    }
  }

  static void Main()
  {
    dynamic x = A | B;
    Console.WriteLine((object)x);
    dynamic y = A & B;
    Console.WriteLine((object)y);

    dynamic xx = A || B;
    Console.WriteLine((object)xx);
    dynamic yy = A && B;
    Console.WriteLine((object)yy);
  }
}



令人惊讶的结果是,这个运行无异常。

The surprising result is that this runs without exception.

好吧, X 不奇怪,他们的声明导致被检索的两个属性,并将得到的值是否达到预期, X 真正

Well, x and y are not surprising, their declarations lead to both properties being retrieved, and the resulting values are as expected, x is true and y is null.

但评估 XX A的> ||乙导致了没有约束力时例外,只有财产 A 被读取,而不是 B 。为什么会这样?正如你所知道的,我们可以改变 B 的getter返回一个疯狂的对象,如的Hello world,和 XX 仍然会评估为真正没有绑定的问题...

But the evaluation for xx of A || B lead to no binding-time exception, and only the property A was read, not B. Why does this happen? As you can tell, we could change the B getter to return a crazy object, like "Hello world", and xx would still evaluate to true without binding-problems...

评估 A和&安培;乙(为 YY )也导致没有约束力时错误。在这里,两个属性被检索的,当然。这是为什么在运行时允许的粘合剂?如果从 B 返回的对象更改为坏的对象(如字符串),有约束力的例外情况发生。

Evaluating A && B (for yy) also leads to no binding-time error. And here both properties are retrieved, of course. Why is this allowed by the run-time binder? If the returned object from B is changed to a "bad" object (like a string), a binding exception does occur.

这是正确的行为?(你怎么可以推断,从规范?)

Is this correct behavior? (How can you infer that from the spec?)

如果您尝试 b 作为第一个操作数,既 b || A B&功放;&安培; A 给运行时绑定异常( B | A B和A 工作细如一切正常与非短路运营商 | &放大器;

If you try B as first operand, both B || A and B && A give runtime binder exception (B | A and B & A work fine as everything is normal with non-short-circuiting operators | and &).

(尝试与Visual Studio 2013和运行时版本的.NET 4.5.2的C#编译器。)

(Tried with C# compiler of Visual Studio 2013, and runtime version .NET 4.5.2.)

推荐答案

首先,感谢您指出该规范是不是在非动态可空,布尔情况清楚。我会解决这个问题在未来的版本。编译器的行为是预期的行为; &放大器;&安培; || 不应该在可空的bool工作

First of all, thanks for pointing out that the spec isn't clear on the non-dynamic nullable-bool case. I will fix that in a future version. The compiler's behavior is the intended behavior; && and || are not supposed to work on nullable bools.

动态粘结剂似乎并没有实现这个限制,虽然。相反,它单独绑定组件操作:在&安培; / | ?: 。因此,它能够如果第一个操作数正好是蒙混过关真正(这是布尔值,从而允许为的第一个操作:),但如果你给作为第一个操作数(例如,如果你尝试 b&功放;&安培; A 中,你得到一个运行时绑定的例外上面的例子)

The dynamic binder does not seem to implement this restriction, though. Instead, it binds the component operations separately: the &/| and the ?:. Thus it's able to muddle through if the first operand happens to be true or false (which are boolean values and thus allowed as the first operand of ?:), but if you give null as the first operand (e.g. if you try B && A in the example above), you do get a runtime binding exception.

如果您认为。关于它,你就会明白为什么我们实施动态&放大器;&安培;以及为 || 这种方式不是一个大动态操作:动态操作在运行时约束的后它们的操作数进行评估的,以便结合可以基于运行时类型这些评价的结果。但是,这种急切的评价击败短路经营的宗旨!所以取而代之,动态生成的代码&放大器;&安培; || 打破了评价成片,将进行如下:

If you think about it, you can see why we implemented dynamic && and || this way instead of as one big dynamic operation: dynamic operations are bound at runtime after their operands are evaluated, so that the binding can be based on the runtime types of the results of those evaluations. But such eager evaluation defeats the purpose of short-circuiting operators! So instead, the generated code for dynamic && and || breaks the evaluation up into pieces and will proceed as follows:


  • 评估左操作数(我们称之为结果 X

  • 尝试通过隐式转换把它变成一个布尔真正运营商(失败,如果不能)

  • 使用 X 作为条件在操作

  • 在真正的分支,使用 X 作为结果

  • 在假分支,的现在的评估第二个操作数(我们称之为结果

  • 尝试在&放绑定; | 运营商的基础上运行的X型(失败,如果不能)

  • 应用选择运营商

  • Evaluate the left operand (let's call the result x)
  • Try to turn it into a bool via implicit conversion, or the true or false operators (fail if unable)
  • Use x as the condition in a ?: operation
  • In the true branch, use x as a result
  • In the false branch, now evaluate the second operand (let's call the result y)
  • Try to bind the & or | operator based on the runtime type of x and y (fail if unable)
  • Apply the selected operator

这是通过操作数的某些非法的组合让行为:运营商成功地将第一个操作数作为一个的非空的的布尔值,在&安培; | 运营商成功地将其视为一个的可为空的布尔值,这两个从来没有协调,以检查他们同意。

This is the behavior that lets through certain "illegal" combinations of operands: the ?: operator successfully treats the first operand as a non-nullable boolean, the & or | operator successfully treats it as a nullable boolean, and the two never coordinate to check that they agree.

所以这不就是动态和放大器;&安培;和||在nullables工作。这只是他们发生在一个方式,是有点过于宽松实施,与静态的情况相比。这也许应该被认为是一个错误,但我们永远不会修复它,因为这将是一个重大更改。此外,它几乎不会帮助任何人收紧的行为。

So it's not that dynamic && and || work on nullables. It's just that they happen to be implemented in a way that is a little bit too lenient, compared with the static case. This should probably be considered a bug, but we will never fix it, since that would be a breaking change. Also it would hardly help anyone to tighten the behavior.

希望这个解释发生了什么,为什么!这是一个有趣的领域,我经常发现自己被当我们实行动态,我们所作的决定带来的后果感到困惑。这个问题很美味 - !感谢您将它

Hopefully this explains what happens and why! This is an intriguing area, and I often find myself baffled by the consequences of the decisions we made when we implemented dynamic. This question was delicious - thanks for bringing it up!

的Mads

这篇关于做短路运算符||和&功放;&安培;有可能为空的布尔值?该RuntimeBinder有时是这样认为的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆