5

Dados dos implementaciones de los métodos de comparación:operador condicional y comparación Delegado

// compares by Key... 
private static int CompareByKey(KeyValuePair<int, string> x, KeyValuePair<int, string> y) 

{ 
    return x.Key.CompareTo(y.Key); 
} 

// compares by Value... 
private static int CompareByValue(KeyValuePair<int, string> x, KeyValuePair<int, string> y) 
{ 
    return x.Value.CompareTo(y.Value); 
} 

¿Por qué no el siguiente condicional operador bloque de código de compilación:

Comparison<KeyValuePair<int, string>> sortMethod; 
sortMethod = isSortByActualValue ? CompareByKey : CompareByValue; 

de error del compilador: "Tipo de expresión condicional no puede se determinará porque no hay una conversión implícita entre 'grupo de métodos' y 'grupo de métodos' "

Sin embargo, el bloque de código equivalente usa if-else d oes no tiene ningún problema:

Comparison<KeyValuePair<int, string>> sortMethod; 
if (isSortByActualValue) 
    sortMethod = CompareByKey; 
else 
    sortMethod = CompareByValue; 

(todo bien en ambas asignaciones anteriores)

también lo hace el operador condicional, si yo echo el delegado Comparación:

Comparison<KeyValuePair<int, string>> sortMethod; 
sortMethod = isSortByActualValue ? (Comparison<KeyValuePair<int, string>>) CompareByKey : CompareByValue; 

(todo bien en el Asignación anterior, cuando se emitió aunque la conversión solo se realizó en la parte verdadera)

+2

¿Cómo se definen CompareByAcutalValue y CompareByDisplayValue? Solo muestra la definición de CompareByKey y CompareByValue. –

+0

El fragmento de código en mi publicación fue editado para mayor claridad. No me di cuenta de que cambié el nombre (de los métodos) solo parcialmente. Gracias Eric, he actualizado todas las referencias a CompareByActualValue para CompareByKey (y CompareByDisplayValue a CompareByValue). – Arun

Respuesta

7

El método de error Th realmente lo dice todo, pero no es muy intuitivo. Si usa un nombre de método sin invocar el método, está manejando un grupo de métodos . "Grupo", porque un método podría estar sobrecargado y el nombre puede indicar cualquiera de los métodos sobrecargados.

Ahora, los grupos de métodos son convertibles implícitamente para un delegado con la firma correspondiente, esta es la razón por la cual su asignación en if funciona.

Hasta ahora, todo bien. Sin embargo, el operador condicional ?: necesita deducir un tipo común para el cual sus argumentos segundo y tercero pueden convertirse implícitamente, y no considera todas las conversiones para eso (esto tendría diversos problemas). Simplemente mira si ambos argumentos tienen el mismo tipo, o si uno es implícitamente convertible en el otro.

Este no es el caso aquí: aunque ambos argumentos son grupos de métodos, de hecho son diferentes grupos de métodos con tipos distintos, y no se puede convertir un grupo de métodos en otro. Aunque ambos pueden convertirse fácilmente en un delegado, el compilador prohíbe este uso.

Lo mismo es cierto para otros tipos, por cierto:

object = someBool ? "" : New List<Integer>(); 

también falla al compilar, por la misma razón. Y una vez más, podemos hacer esta compilación por colada ya sea de forma explícita de los argumentos de un tipo base común:

object = someBool ? (object) "" : New List<Integer>(); 
+1

+1, pero cambiaría "necesita deducir el tipo de su segundo y tercer argumento" por "necesita deducir un tipo común para el cual sus argumentos segundo y tercero se pueden convertir implícitamente" – phoog

+0

¿Por qué no 'isSortByActualValue ? CompareByKey: compilación CompareByKey'? ¿No son el mismo grupo de métodos? – svick

+0

@svick No existe una conversión del grupo de métodos al grupo de métodos, independientemente del grupo de métodos. Debería haber dejado eso más claro, y es un caso bastante particular ya que ningún tipo común carece de esta conversión. No sé cómo esto se establece con precisión en la especificación C#. –

3

Si usted tiene una expresión como su CompareByKey, no tiene ningún tipo de .NET específica, pero tiene un tipo especial "grupo de métodos". Esto se debe a que podría tener varios métodos llamados CompareByKey y no está claro cuál es el que desea (y funciona exactamente igual aunque tenga solo un método). Además, no está claro qué tipo de delegado desea, p. Ej. Comparison<KeyValuePair<int, string>> o Func<KeyValuePair<int, string>, int>.

¿Qué se puede hacer con los grupos de métodos? Puede usarlos para crear explícitamente un delegado (new Comparison<KeyValuePair<int, string>>(CompareByKey)) y también son implícitamente convertibles en delegados. Es por eso que su versión if funciona.

Entonces, ¿qué tiene eso que ver con su problema? Cuando tienes un operador condicional, el compilador tiene que averiguar el tipo de la expresión completa y no puede usar el tipo de la variable a la que lo asignas (no es así como funciona la inferencia de tipo en C#). Y dado que ambas expresiones son grupos de métodos y los grupos de métodos se tratan como tipos diferentes sin conversiones implícitas entre sí, no se puede determinar el tipo de la expresión completa. Por eso obtienes el error.

Ya encontró una solución: o bien no utiliza el operador condicional o especifica el tipo de uno de los operandos de forma explícita utilizando un molde (o un constructor delegado).

Cuestiones relacionadas