Hacer operadores de cortocircuito || y && existen para booleanos anulables? The RuntimeBinder a veces piensa que sí

Leí la especificación del lenguaje C # en elOperadores lógicos condicionales || y&&, también conocidos como operadores lógicos de cortocircuito. Para mí, no estaba claro si estos existían para booleanos anulables, es decir, el tipo de operandoNullable<bool> (también escritobool?), así que lo probé con la escritura no dinámica:

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

Eso pareció resolver la pregunta (no podía entender la especificación claramente, pero suponiendo que la implementación del compilador de Visual C # era correcta, ahora lo sabía).

Sin embargo, quería probar condynamic vinculante también. Así que intenté esto en su lugar:

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);
  }
}

El resultado sorprendente es que esto se ejecuta sin excepción.

Bien,x yy no son sorprendentes, sus declaraciones conducen a la recuperación de ambas propiedades y los valores resultantes son los esperados,x estrue yy esnull.

Pero la evaluación paraxx deA || B no conducen a ninguna excepción de tiempo de enlace, y solo la propiedadA fue leído, noB. ¿Por qué pasó esto? Como puede ver, podríamos cambiar elB getter para devolver un objeto loco, como"Hello world"yxx aún evaluaría atrue sin problemas vinculantes ...

EvaluandoA && B (parayy) tampoco conduce a ningún error de tiempo de enlace. Y aquí se recuperan ambas propiedades, por supuesto. ¿Por qué está permitido por la carpeta de tiempo de ejecución? Si el objeto devuelto deB se cambia a un objeto "malo" (como unstring), se produce una excepción vinculante.

¿Es este el comportamiento correcto? (¿Cómo puedes inferir eso de la especificación?)

Si intentasB como primer operando, ambosB || A yB && A dar excepción de carpeta de tiempo de ejecución (B | A yB & A funciona bien ya que todo es normal con operadores que no están en cortocircuito| y&)

(Probado con el compilador C # de Visual Studio 2013 y la versión de ejecución .NET 4.5.2.)

Respuestas a la pregunta(3)

Su respuesta a la pregunta