c# - usar - Declaración condicional, delegado genérico molde innecesario
operadores ternarios c# (4)
Estoy teniendo este problema realmente extraño con un enunciado condicional cuando establezco un valor de Action<T>
. No es que no sepa cómo evitar esto, ya que es bastante fácil de resolver usando un if
normal.
Aquí está mi problema:
public class Test
{
public bool Foo { get; set; }
public Action<bool> Action { get; set; }
public void A()
{
Action = Foo ? B : C;//Gives compiler error
}
public void B(bool value)
{
}
public void C(bool value)
{
}
}
Esto me da un error de compilación con el mensaje
No hay conversión implícita entre ''grupo de métodos'' y ''grupo de métodos''.
Lo cual es extraño ya que no puedo entender por qué esto sería ilegal.
Por cierto, la sintaxis siguiente lo hará válido (desde el punto de vista de los compiladores):
public void A()
{
Action = Foo ? (Action<bool>) B : C;
}
Entonces quizás puedas leer la pregunta como, ¿por qué es necesario el elenco?
Porque B
y C
no son en realidad delegados. Son grupos de métodos y pueden convertirse implícitamente en delegados (en particular, Action<bool>
), pero eso no es lo mismo.
El tipo de expresión condicional debe ser coherente en ambas ramas, y dado que B
y C
son actualmente grupos de métodos (que no están tipados), el compilador no puede determinar cuál debe ser el tipo. Como te dice, no hay una conversión implícita entre ellos.
Además, no puede (o al menos no lo hace ) mirar hacia el otro lado del operador de asignación y decir "oh, debería ser Action<bool>
".
Cuando agrega un molde, el tipo de la expresión de la rama izquierda se convierte en Action<bool>
, y hay una conversión implícita entre el grupo de métodos en el otro lado y ese delegado, por lo que el compilador está feliz otra vez: el tipo de la expresión completa es Action<bool>
.
Una Acción es una clase de delegado específica, y no hay una conversión implícita disponible desde / hacia un delegado regular con una firma similar.
Usted está combinando dos conceptos similares:
A) Un grupo de métodos. Un grupo de métodos es uno o más métodos de C # con el mismo nombre. Es una abstracción utilizada principalmente por el compilador; no puedes pasar a un grupo de métodos. Todo lo que puede hacer con un grupo de métodos es invocarlo o crear un delegado a partir de él. Puede crear implícitamente un delegado de un grupo de métodos si las firmas de tipo coinciden.
B) Un delegado. Usted sabe lo que es un delegado; tiene una firma de tipo específico y se refiere directamente a un método. Además de invocarlo, puedes pasarlo por alto y tratarlo como un objeto de primera clase.
Entonces, en el primer ejemplo, su expresión devuelve un grupo de métodos B
en un lado y otro grupo de métodos C
en el otro lado. El operador ternario necesita devolver el mismo tipo en ambos lados, pero no sabe a qué lado lanzarlo; el tipo de variable al que asignó el resultado ( Action<bool>
) no determina el tipo de la expresión. Entonces es ambiguo
En el segundo ejemplo, legalmente se envía el grupo B
del método a un delegado Action<bool>
en un lado del operador ternario. En el proceso de intentar desambiguar la expresión, el compilador intenta convertir cada lado al tipo del otro lado. Puede lanzar con éxito el grupo de métodos C
a una Action<bool>
, por lo que lo hace y la expresión es legal.
Creo que Eric me volverá a decir que mi razonamiento es ligeramente incorrecto , pero lo intentaré de todos modos y espero que lo corrijan :-)
Un grupo de métodos, por ejemplo B
, no tiene un tipo, no es un objeto ( B.GetType()
no se va a compilar).
Se puede convertir fácilmente en un tipo, por eso existe un molde implícito. Muestra:
Action<bool> a = B; // implicit cast taking place.
Sin embargo, como puede ver en la pregunta vinculada, la expresión ternaria intenta encontrar un tipo de retorno que coincidan con ambas partes de la expresión. No sabe que luego debería pasar una conversión a Action<bool>
. Debido a que los grupos de métodos no son tipos per se, no existe conversión entre ellos y B
no se puede convertir a C
y, por lo tanto, el compilador se queja de eso.
Al convertir cualquiera de las partes de la expresión ternaria en Action<bool>
, le dice al compilador que el tipo de retorno debe ser de ese tipo y verifica si la otra parte de la expresión ternaria admite un lanzamiento implícito a ese tipo. Porque este es el caso, el código compilará.