2010-04-06 26 views
22

que tienen un fragmento pequeño y sencillo código que me está frustrando:Operador condicional C# ¿No es una declaración?

HashSet<long> groupUIDs = new HashSet<long>(); 
groupUIDs.Add(uid)? unique++ : dupes++; 

En tiempo de compilación, se genera el error:

Only assignment, call, increment, decrement, and new object expressions can be used as a statement

HashSet.Add se documenta para devolver un bool, por lo que el ternario (?) el operador debería funcionar, y esto parece una forma completamente legítima de rastrear la cantidad de elementos únicos y duplicados que agrego a un conjunto de hash.

Cuando lo vuelvo a formatear como un if-then-else, funciona bien.

¿Alguien puede explicar el error, y si hay una manera de hacerlo como un simple operador ternario?

+1

Prefiero el if statemnet en su lugar. La variable de asignación ficticia que sugieren algunas respuestas solo agrega confusión. –

+4

También tenga en cuenta que los ternarios se usan generalmente para elegir un valor, no para elegir una acción. En su caso, usted está eligiendo si incrementar uno o dos valores. Por lo tanto, tiene más sentido semántico usar un if-else ya que está eligiendo una acción. – AaronLS

Respuesta

19

De acuerdo con el mensaje de error, el operador ternario no se puede utilizar como una declaración. Usted tendría que hacer algo como esto para convertirlo en una misión:

int dummy = groupUIDs.Add(uid)? unique++ : dupes++; 

Dicho esto, me gustaría recomendar a utilizar solo si-entonces-else. Es menos confuso porque no implica la creación de variables ficticias "mágicas" ...

+1

Esto parece arreglalo. En C, no hay nada malo con un ternario independiente que no hace nada. Aparentemente esto no es verdad en C#. Gracias. – abelenky

+9

O use un operador if en lugar del ternario, en lugar de asignar un valor a una variable inútil por el bien de la frialdad del código y en detrimento de la legibilidad. – ANeves

+1

una instrucción if completamente formateada toma 8 líneas con un nivel de sangría adicional. Parece una gran pérdida para una operación tan simple. Estoy extremadamente cómodo con ternario como programador de C/C++, y no veo ningún factor interesante o que dañe la legibilidad. – abelenky

4

El compilador no se queja de Add se queja del hecho de que su expresión condicional no es una declaración completa.

Algunos lenguajes (como JavaScript) le permiten usar una expresión condicional para la lógica de bifurcación como lo hizo aquí, pero C# requiere que asigne el resultado de la expresión condicional a una variable. Una vez que asigna el resultado de la expresión, ha hecho una declaración completa y el compilador está contento.

+4

En realidad, se está quejando del operador ternario. –

+0

@Andrew ¿No se considerarían estos como un incremento, que se menciona en el mensaje de error como una declaración válida? – AaronLS

+0

@Merhdad - Sí, tienes razón - Lo estoy arreglando ahora. –

7

No está estableciendo el valor del resultado del ternario para nada por eso.

HashSet<long> groupUIDs = new HashSet<long>(); 
int count = groupUIDs.Add(uid)? unique++ : dupes++; 
5

El operador ternario no es una afirmación. Por lo tanto, no puede ser utilizado solo en una instrucción - que es el equivalente a escribir

"something that is not a statement"; 

Para aclarar, usted debe tomar el operador ternario y utilizar un si.

+0

En C y C++ al menos, es una declaración perfectamente válida (aunque sin efectos secundarios). Aparentemente esto no es verdad en C#. Resulta que la respuesta correcta es tener una asignación ficticia como @sth sugirió. – abelenky

+0

Esta es una gran explicación, porque si piensas cómo funciona un ternario, se evalúa con un valor único, el valor que se elige entre las dos opciones. Entonces una vez evaluado es como escribir el enunciado que es el valor de 'unique;' (después de ser incrementado), o 'dupes;' que sería algo así como '12345;' que no sería una declaración válida ya que es solo un entero solitario. – AaronLS

+1

@ AaronLS: En primer lugar, sería el valor de único antes de incrementar, no después. En segundo lugar, en muchos idiomas, tener un entero único es perfectamente válido. C# es diferente a este respecto. – abelenky

0

Si esto no es aceptable, ¿por qué sería su línea? Solo use una instrucción if :-)

 bool b = false; 
     b?callB():callA(); 
1

gmcalab y sr pt tienen razón; El operador ternario está destinado a darle un resultado, al igual que 1 + 1 le da 2. No puede simplemente escribir:

1 + 1;

La confusión aquí (creo) es que estás pensando en el operador ternario como si fuera una función.

2

Necesita usar el valor del operador ternario para algo ...

HashSet<long> groupUIDs = new HashSet<long>(); 
int newCount = groupUIDs.Add(uid)? unique++ : dupes++; 

o - el uso de un if

HashSet<long> groupUIDs = new HashSet<long>(); 
if (groupUIDs.Add(uid)) 
    unique++; 
else 
    dupes++; 
1

El description del operador ternario en la referencia del lenguaje dice que

If condition is true, first expression is evaluated and becomes the result; if false, the second expression is evaluated and becomes the result.

Parece que el ternario sólo se puede utilizar en el contexto de asignación, aunque la referencia del lenguaje no lo explicita. No estás haciendo una tarea en el resultado.

En mi opinión, la reescritura como if/else sería más clara.

+0

No tiene que ser una tarea; por ejemplo, podría pasarlo a otro método. –

+0

Tienes razón, tenía prisa y mi redacción era demasiado floja. –

16

Como han señalado otros, el operador condicional no es una expresión de enunciado legal. (Las expresiones del enunciado legal son asignaciones, llamadas, incrementos, decrementos y construcciones).

Sin embargo, aquí también hay un problema de estilo. En mi opinión, las expresiones deberían ser útiles para sus valores, y las declaraciones deberían ser útiles por sus efectos secundarios. Lo que te encuentras es que tienes una expresión que solo es útil por su efecto secundario, y que es un mal olor a código.

Tiene un efecto secundario, por lo tanto, utilice una instrucción condicional en lugar de una expresión condicional.

+1

Por respeto a @EricLippert, lo cambiaré a una declaración condicional, if-else. Otro paso en la curva de aprendizaje de C a C#. – abelenky

+8

@abelenky: Me siento halagado, pero por favor, no lo hagas por mi bien. Hágalo por el bien de las personas futuras que deben mantener su código. :-) –