Operadores de curto-circuito || e && existem para booleanos anuláveis? O RuntimeBinder às vezes pensa assim

Eu li a Especificação da linguagem C # noOperadores lógicos condicionais || e&&, também conhecidos como operadores lógicos em curto-circuito. Para mim, não parecia claro se existiam para booleanos anuláveis, ou seja, o tipo de operandoNullable<bool> (também escritobool?), então tentei com digitação não dinâmica:

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

Isso pareceu resolver a questão (não consegui entender claramente a especificação, mas assumindo que a implementação do compilador Visual C # estava correta, agora eu sabia).

No entanto, eu queria tentar comdynamic obrigatório também. Então, eu tentei isso:

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

O resultado surpreendente é que isso ocorre sem exceção.

Bem,x ey não são surpreendentes, suas declarações levam a que ambas as propriedades sejam recuperadas e os valores resultantes são os esperados,x étrue ey énull.

Mas a avaliação paraxx doA || B levar a nenhuma exceção de tempo de ligação e apenas a propriedadeA foi lido, nãoB. Por que isso acontece? Como você pode ver, podemos mudar oB getter para retornar um objeto louco, como"Hello world"exx ainda avaliariatrue sem problemas de ligação ...

AvaliandoA && B (parayy) também leva a nenhum erro no tempo de ligação. E aqui as duas propriedades são recuperadas, é claro. Por que isso é permitido pelo fichário de tempo de execução? Se o objeto retornado deB é alterado para um objeto "ruim" (como umstring), ocorre uma exceção de ligação.

Esse comportamento é correto? (Como você pode inferir isso das especificações?)

Se você tentarB como primeiro operando, ambosB || A eB && A dar exceção do fichário de tempo de execução (B | A eB & A funciona bem, pois tudo é normal com operadores sem curto-circuito| e&)

(Tentei com o compilador C # do Visual Studio 2013 e a versão de tempo de execução .NET 4.5.2.)

questionAnswers(3)

yourAnswerToTheQuestion