2008-08-28 8 views
103

Hay dos operadores extraños en C#:¿Para qué sirve el falso operador en C#?

Si entiendo este derecho estos operadores pueden utilizarse en tipos que quiero utilizar en lugar de un valor lógico expresión y donde no deseo proporcionar una conversión implícita a bool.

Digamos que tengo una clase siguiente:

public class MyType 
    { 
     public readonly int Value; 

     public MyType(int value) 
     { 
      Value = value; 
     } 

     public static bool operator true (MyType mt) 
     { 
      return mt.Value > 0; 
     } 

     public static bool operator false (MyType mt) 
     { 
      return mt.Value < 0; 
     } 

    } 

, así que puede escribir el siguiente código:

MyType mTrue = new MyType(100); 
    MyType mFalse = new MyType(-100); 
    MyType mDontKnow = new MyType(0); 

    if (mTrue) 
    { 
     // Do something. 
    } 

    while (mFalse) 
    { 
     // Do something else. 
    } 

    do 
    { 
     // Another code comes here. 
    } while (mDontKnow) 

Sin embargo, para todos los ejemplos anteriores sólo el verdadero operador se ejecuta. Entonces, ¿para qué sirve el falso operador en C#?

Nota: Más ejemplos se pueden encontrar here, here y here.

+0

Documentos modernos se pueden encontrar en https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/false-operator. Los documentos sugieren que no hay ninguna razón para definir este operador más ya que C# 2.0 agregó tipos anulables. –

Respuesta

61

Puede usarlo para anular los operadores && y ||.

Los && y || operadores no pueden ser anulados, pero si se reemplaza |, &, true y false exactamente de la manera correcta el compilador llamarán | y & cuando se escribe || y &&.

Por ejemplo, un vistazo a este código (de http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - donde me enteré de este truco; archived version por @BiggsTRC):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs) 
{ 
     return new AndExpression(lhs, rhs); 
} 

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs) 
{ 
     return new OrExpression(lhs, rhs); 
} 

public static bool operator false(AbstractCriterion criteria) 
{ 
     return false; 
} 
public static bool operator true(AbstractCriterion criteria) 
{ 
     return false; 
} 

Esto es obviamente un efecto secundario y no la forma en que está destinado a ser usado, pero es útil.

+4

+1 Es un truco genial. Buen hallazgo! –

+0

su enlace es 404. No estoy seguro de cómo quiere editar esto, así que lo he dejado. – user7116

+0

Actualicé la URL con una copia archivada para que aún se pueda leer. – IAmTimCorey

14

La página que enlaza con http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx indica para qué eran, que era una forma de manejar boles nullable antes de que se introdujeran los tipos de valores anulables.

Supongo que hoy en día son buenos para el mismo tipo de cosas que ArrayList, es decir, absolutamente nada.

3

Parece que desde el artículo de MSDN al que se ha vinculado se proporcionó para permitir tipos booleanos que aceptan nulos antes de introducir el tipo Nullable (es decir, bool ?, etc.) en el lenguaje en C# 2. Por lo tanto, almacenaría un valor interno que indica si el valor es verdadero o falso o nulo, es decir, en su ejemplo> 0 para verdadero, < 0 para falso y == 0 para nulo, y luego obtendría semántica nula de estilo SQL. También debería implementar un método o propiedad .IsNull para que la nulidad se pueda verificar explícitamente.

Comparando con SQL, imagina una tabla Tabla con 3 filas con valor Foo establecido en verdadero, 3 filas con valor Foo establecido en falso y 3 filas con valor Foo establecido en nulo.

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE 
6 

Para contar todas las filas que tendría que hacer lo siguiente: -

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL 
9 

Este 'es nulo' sintaxis tendría código equivilent en su clase como .IsNull().

LINQ hace que la comparación con C# aún más claro: -

int totalCount = (from s in MyTypeEnumerable 
       where s || !s 
       select s).Count(); 

Imaginando que MyTypeEnumberable tiene exactamente los mismos contenidos de la base de datos, es decir, 3 valores igual a verdadero, 3 valores iguales a falso y 3 valores igual a nulo. En este caso, totalCount evaluaría a 6 en este caso. Sin embargo, si nos re-escribió el código como: -

int totalCount = (from s in MyTypeEnumerable 
       where s || !s || s.IsNull() 
       select s).Count(); 

Entonces totalCount evaluaría a 9.

El ejemplo DBNull dado en el artículo MSDN vinculado en el operador falso muestra una clase en el BCL que tiene este comportamiento exacto.

En efecto, la conclusión es que no debes usar esto a menos que estés completamente seguro de que quieres este tipo de comportamiento, ¡es mejor usar la sintaxis nullable mucho más simple!

Actualización: Acabo de notar que necesita anular manualmente los operadores lógicos!, || y & & para hacer que esto funcione correctamente. Creo que el operador falso alimenta estos operadores lógicos, es decir, indica la verdad, la falsedad o "de lo contrario". Como se señaló en otro comentario! X no funcionará fuera del bate; tienes que sobrecargar! ¡Rareza!

7

AFAIK, se usaría en una prueba de falsa, como cuando el operador && entra en juego. Recuerde, & & cortocircuitos, por lo que en la expresión

if (mFalse && mTrue) 
{ 
    // ... something 
} 

mFalse.false() se llama, y ​​al regresar true la expresión se reduce a una llamada a 'mFalse.true()' (que luego debe volver false, o las cosas se pondrán raras).

Tenga en cuenta que debe implementar el operador & para que esa expresión se compile, ya que se usa si mFalse.false() devuelve false.

21

Shog9 y Nir: gracias por sus respuestas. Esas respuestas me apuntaron a Steve Eichert article y me apuntaron a msdn:

La operación x & & y se evalúa como T.false (x)? x: T. & (x, y), donde T.false (x) es una invocación del operador falso declarado en T, y T. & (x, y) es una invocación del operador seleccionado &. En otras palabras, x se evalúa primero y el operador falso se invoca en el resultado para determinar si x es definitivamente falso. Entonces, si x es definitivamente falso, el resultado de la operación es el valor previamente calculado para x. De lo contrario, se evalúa y y se invoca el operador seleccionado & en el valor calculado previamente para xy el valor calculado para y para producir el resultado de la operación.