2011-08-16 12 views
8

Estoy teniendo este problema realmente extraño con una declaración condicional al establecer 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.Declaración condicional, delegado genérico, conversión innecesaria

Aquí es 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 Método' y 'grupo Método'.

Lo que es extraño ya que no puedo entender por qué esto sería ilegal.

Por cierto, la siguiente sintaxis hará que esta válida (desde el punto de vista compiladores):

public void A() 
    { 
     Action = Foo ? (Action<bool>) B : C; 
    } 

Así que tal vez se puede leer la pregunta, ¿por qué es necesario el elenco?

Respuesta

2

Estás confundir dos conceptos similares:

a) un grupo método. 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.

Por lo tanto, en el primer ejemplo, su expresión devuelve un grupo de métodos B por 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 expresión. Entonces es ambiguo

En el segundo ejemplo, legalmente se envía el grupo de métodos B 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 Action<bool>, por lo que lo hace y la expresión es legal.

-1

Una acción es una clase de delegado específica, y no hay una conversión implicit disponible de/a un delegado regular con una firma similar.

+0

pensé que el compilador de C# es lo suficientemente inteligente como para comprobar que ... –

1

Porque B y C no son realmente delegados. Son grupos de métodos, y se pueden convertir 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 tipeados), el compilador no puede determinar cuál debe ser el tipo. Como te dice, no hay una conversión implícita entre ellos.

A su vez, no puede (o al menos no ) mira hacia el otro lado del operador de asignación y decir "oh, debe ser Action<bool>".

Cuando se agrega un yeso, el tipo de la expresión rama izquierda se convierte en Action<bool>, y hay es una conversión implícita entre el grupo método sobre el otro lado y que el delegado, por lo que el compilador es feliz de nuevo: el tipo de toda la expresión es Action<bool>.

0

creo, Eric will again tell me, that my reasoning is slightly incorrect, pero voy a darle una oportunidad de todos modos y esperanza para su corrección :-)

Un grupo de métodos, por ejemplo B, no tiene un tipo, no es un objeto (B.GetType() no 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 se puede ver en la cuestión vinculada, la expresión ternaria trata de encontrar un tipo de retorno que ambas partes de la coincidencia de expresión. No sabe que más tarde una conversión a Action<bool> debería ocurrir.Como los grupos de métodos no son tipos per se, no existe ninguna conversión entre ellos y B no pueden convertirse 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 comprueba si la otra parte de la expresión ternaria admite un molde implícito para ese tipo. Porque este es el caso, el código compilará.

Cuestiones relacionadas