2011-03-30 25 views
31

Mientras jugaba con nuevos conceptos, me encontré con el Ternary Operator y su belleza. Después de jugar con él por un tiempo, decidí probar sus límites.Llamada a un método usando Operador Ternario

Sin embargo, mi diversión se terminó rápidamente cuando no pude obtener una cierta línea de código para compilar.

int a = 5; 
int b = 10; 
a == b ? doThis() : doThat() 

    private void doThis() 
    { 
     MessageBox.Show("Did this"); 
    } 
    private void doThat() 
    { 
     MessageBox.Show("Did that"); 
    } 

Esta línea me da dos errores:

Error 1 Only assignment, call, increment, decrement, and new object expressions can be used as a statement 
Error 2 Type of conditional expression cannot be determined because there is no implicit conversion between 'void' and 'void' 

que nunca han usado una Ternary Operator decidir el método que se llama, ni sé si es aún posible. Simplemente me gusta la idea de una línea If Else Statement para llamadas de método.

He hecho un poco de investigación y no puedo encontrar ningún ejemplo de alguien haciendo esto, así que creo que podría estar esperando algo que no pueda proporcionar.

Si esto es posible, por favor aclararme en mis acciones incorrectas, y no es posible, ¿hay alguna otra manera?

+1

Asegúrese de que las funciones doThis y doThat devuelven un valor de tipo int. – Chandu

+0

Vaya, déjame publicar mis métodos muy rápido. –

+1

Si realmente desea un 'de línea única', simplemente escríbalo como una línea: 'if (condición) doThis(); else doThat(); 'De acuerdo, el operador ternario (si funcionó de la manera en que pensaste) sería más corto, pero la concisión no siempre es algo bueno. –

Respuesta

2

La razón por la declaración anterior no trabajo fue proporcionado por los otros usuarios y efectivamente no lo hizo responde mi verdadera pregunta

Después de jugar un poco más, me di cuenta de que se puede utilizar este operador para hacer la declaración anterior, pero da lugar a una mala código.

Si tuviera que cambiar la declaración anterior a;

int a = 5; 
int b = 10; 
int result = a == b ? doThis() : doThat(); 

private int doThis() 
{ 
    MessageBox.Show("Did this"); 
    return 0; 
} 
private int doThat() 
{ 
    MessageBox.Show("Did that"); 
    return 1; 
} 

Este código se compilará y ejecutará como debería. Sin embargo, si estos métodos originalmente no estaban destinados a devolver nada, y se hace referencia a otras áreas en el código, ahora tiene que manejar un objeto de retorno cada vez para llamar a estos métodos.

De lo contrario, ahora se puede utilizar un operador ternario de un método selector de una línea e incluso saber qué método se llama en la siguiente línea con el resultado.

int result = a == b ? doThis() : doThat(); 

if (result == 0) 
    MessageBox.Show("You called doThis()!"); 

Ahora, este código es absolutamente inútil y podría hacerse fácilmente por un Else Si, pero yo sólo quería saber si se podía hacer, y lo que había que hacer para conseguir que funcione.

Ahora que sé que puede volver de manera efectiva cualquier tipo en estos métodos, esto podría ser un poco más útil. Se puede considerar una "Práctica mala de codificación" pero podría ser muy útil en situaciones para las que nunca fue MEJOR.

Se puede obtener acceso a un objeto u otra basada en cualquier condición y que puede ser muy útil en una línea de código.

UserPrivileges result = user.Group == Group.Admin ? GiveAdminPrivileges() : GiveUserPrivileges(); 

private UserPrivileges GiveAdminPrivileges() 
{ 
     //Enter code here 
     return var; 
} 
private UserPrivileges GiveUserPrivileges() 
{ 
     //Enter code here 
     return var; 
} 

Claro, esto se puede hacer mediante una instrucción IF, pero creo que el uso del operador ternario para otros usos se burla de programación. Ahora, esto puede no ser tan eficiente como una declaración If Else, en cuyo caso, nunca usaría esto.

+4

No hay ** realmente ** no tiene sentido hacer eso. – SLaks

+0

De acuerdo, pero para completar, también podría devolver un bool, cuerda o cualquier objeto en realidad. Pero realmente, ¿qué dice la afirmación 1? realmente significa para un compilador? No mucho, y no ayuda a los matices de aprender buenas prácticas de codificación – Michael

+0

@Michael No sabía eso, y ese es el punto de mi pregunta. Quería saber cómo hacer que esto funcione y los beneficios/consecuencias de usarlo. La posibilidad de elegir un tipo de devolución lo hace aún más útil. –

15

operador ternario debe devolver algo. Un uso típico es la siguiente:

int x = (a > b) ? a : b; 

Si intenta algo así como

a + b; 

El compilador se quejará.

(a > b) ? a - b : b - a; 

es básicamente un acceso directo, ya sea para "A - B" o "b - a", que no son declaraciones legítimas por su cuenta.

+5

+1. Si DoThis() y DoThat() devolvían algo, podría usar el ternario para controlar la ejecución y asignar el resultado a alguna variable local, sin embargo, esta no es la intención del operador ternario; otros desarrolladores pensarían que el valor de retorno fue más significativo para usted que los efectos secundarios. Use una declaración if básica; sus intenciones permanecerán claras (y no tiene que meterse con sus firmas de métodos solo para ser inteligente). – KeithS

+4

+1, Otro punto clave es que ambos valores que pueden ser devueltos por el operador ternario deben ser del mismo tipo o implícitamente convertibles al mismo tipo. –

31

El operador ternario se utiliza para devolver valores y esos valores deben asignarse. Suponiendo que los métodos doThis() y doThat() devuelven valores, una asignación simple solucionará su problema.

Si quiere hacer lo que está intentando, es posible, pero la solución no es bonita.

int a = 5; 
int b = 10; 
(a == b ? (Action)doThis : doThat)(); 

Esto devuelve un delegado de acción que luego es invocado por el paréntesis. Esta no es una forma típica de lograr esto.

+1

De hecho, no es la forma correcta de hacer las cosas; pero definitivamente la respuesta más correcta a la pregunta: el OP quería usar el operador ternario para elegir un método para llamar, y eso es exactamente lo que hace su fragmento;) –

+0

¿Por qué esto no es "correcto"? Otro cartel fue tan lejos como para llamarlo tonto. – Morgoth

+0

La respuesta es que es sustancialmente más lento http://www.dotnetperls.com/action – Morgoth

1

El operador condicional es una expresión que devuelve un valor.
No puede usarlo con funciones que devuelven void.

En su lugar, debe utilizar un if normal.

+0

Sin embargo, tal vez el OP suponía que los usuarios podían usar el operador condicional en una sintaxis de estilo C/C++, donde la sintaxis permitiría al usuario llamar a un método dentro de una operación condicional. Pero supongo que por lo que dijo el OP, no basaron su uso del operador condicional en la sintaxis C/C++. – Jake

1

.NET no admite (fácilmente) (una versión legible de) esto por algún motivo. Es muy jankity y hace que tu código sea difícil de leer. Los árboles lógicos deberían ser relativamente fáciles de atravesar. Si tuviera que ir a un trabajo y todo el código que utilizaron ternario para asignar valores, métodos de llamada, etc. Creo que simplemente me iré.

+0

Aún necesita una asignación. – NerdFury

+0

Creo que la única forma en que esto haría que el código sea difícil de leer es si usaste nombres de variables no descriptivas y números mágicos (números que parecen no tener ningún significado). Si un operador ternario se usa correctamente, debe leer tan fácil como un If/Else. –

+0

Los nombres de los métodos pueden ser largos y con frecuencia implican parámetros. No quiero tener que leer una línea de 200 caracteres para descubrir dónde se inicia una llamada de método y la otra finaliza. Múltiples líneas (al menos para mí) es generalmente más fácil de leer y casi nunca requiere líneas de varias líneas. Compare con: '(VicePresidentsAttendee.AnnualSalary == MoneyHelper.MonetizeInt (SalaryThreshold))? RaiseHelper.AddABillionDollarBonus (VicePresidentAttendee.PersonId): RaiseHelper.RegisterPersonForYearlyRaise (SalaryThreshold, PersonId, SickDaysLastQuarter, TypingSpeedInGoalWordsPerMinute, LunarPhaseOnLastPiDay); ' – FreeAsInBeer

2

Usted debe ser capaz de hacer esto, sin embargo:

 int a = 5; 
     int b = 10; 

     var func = a == b ? (Action)doThis : (Action)doThat; // decide which method 

     func(); // call it 

No es que esto es realmente útil

7

Si realmente desea invocar void métodos en un operador condicional, puede utilizar delegados:

(something ? new Action(DoThis) : DoThat)(); 

Si los métodos toman parámetros, esto se hará más complicada.
Puede poner expresiones lambda en el condicional o usar Action<T>.

Sin embargo, esto es una cosa muy tonta para hacerlo.

Cuestiones relacionadas