2009-05-14 8 views
5

Ver las cuatro líneas en el Go() método siguiente:La diferencia entre la creación delegado implícita y explícita (con y sin genéricos)

delegate void Action<T>(T arg); 
delegate void Action(); 

void DoSomething<T>(Action<T> action) 
{ 
    //... 
} 

void DoSomething(Action action) 
{ 
    //... 
} 

void MyAction<T>(T arg) 
{ 
    //... 
} 

void MyAction() 
{ 
    //... 
} 

void Go<T>() 
{ 
    DoSomething<T>(MyAction<T>); // throws compiler error - why? 
    DoSomething(new Action<T>(MyAction<T>)); // no problems here 
    DoSomething(MyAction); // what's the difference between this... 
    DoSomething(new Action(MyAction)); // ... and this? 
} 

Tenga en cuenta que el error del compilador generada por la primera llamada es: Los argumentos de tipo para el método 'Acción (T)' no se pueden deducir del uso. Intente especificar los argumentos de tipo explícitamente.

+0

No puedo entender cómo esto podría compilar (aisladamente): vacío HacerAlgo (Acción acción) { // ...} Como T no se declara ... Es todo el interior una clase genérica? –

+0

Sí, estoy modificando mi ejemplo ahora. Debería haber leído Go () {... –

+0

Soy yo, pero cuando compilo el código que tienes aquí compila sin ningún error.Suponiendo que coloque el código en una clase no genérica. Estoy usando C# 3.5 SP1 – JoshBerke

Respuesta

13

No hay diferencia entre MyAction y new Action(MyAction) (cuando los dos son válidos) que no sea el primero no funciona en C# 1. Esta es una implicit method group conversion. Hay momentos en que esto no es aplicable, más notable cuando el compilador no puede determinar qué tipo de delegado desea, p.

Delegate foo = new Action(MyAction); // Fine 
Delegate bar = MyAction; // Nope, can't tell target type 

Esto entra en juego en su pregunta porque ambos métodos están sobrecargados. Esto lleva a dolores de cabeza, básicamente.

En cuanto al lado de los genéricos, es interesante. Los grupos de métodos no reciben mucho amor de la inferencia de tipo C# 3: no estoy seguro de si se mejorará en C# 4 o no. Si se llama a un método genérico y se especifica el argumento de tipo, la inferencia de tipos funciona bastante bien - pero si se intenta hacerlo a la inversa, se produce un error:

using System; 

class Test 
{ 
    static void Main() 
    { 
     // Valid - it infers Foo<int> 
     DoSomething<int>(Foo); 
     // Valid - both are specified 
     DoSomething<int>(Foo<int>); 
     // Invalid - type inference fails 
     DoSomething(Foo<int>); 
     // Invalid - mismatched types, basically 
     DoSomething<int>(Foo<string>); 
    } 

    static void Foo<T>(T input) 
    { 
    } 

    static void DoSomething<T>(Action<T> action) 
    { 
     Console.WriteLine(typeof(T)); 
    } 
} 

La inferencia de tipos en C# 3 es muy complicado, y funciona bien en la mayoría de los casos (en particular, es genial para LINQ) pero falla en algunos otros. En un mundo ideal, sería más fácil de entender y más potente en las versiones futuras ... ya veremos!

+0

¡Salud! Acepté la otra respuesta, pero la tuya sigue siendo útil también. +1 –

3

El no genérico creación delegado implícita es sólo azúcar sintáctico, por lo que el compilador genera exactamente el mismo código para

DoSomething(MyAction); 

y

DoSomething(new Action(MyAction)); 

ya que puede deducir el tipo del delegado directamente desde el argumento del método &.

Con el delegado genérico, debe especificar el tipo de delegado debido a la covarianza y la contravarianza (consulte http://msdn.microsoft.com/en-us/library/ms173174(VS.80).aspx para obtener más detalles) - la T en Acción puede ser un supertipo de la T en el método, y aún se aceptará como un método delegado. Por lo tanto, debe especificar la T en el delegado explícitamente ya que el compilador no puede resolverlo por sí mismo.

+0

Saludos, ahora lo entiendo. Enlace al artículo de covarianza vs contravarianza para aquellos que no entienden: http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) –

+0

Diría que tiene más que ver con las limitaciones de la inferencia de tipo que con la co/contravariancia, personalmente. Si lees la sección de especificaciones sobre la inferencia de tipo (no puedo recordarlo ahora) verás que los grupos de métodos básicamente no tienen muchas posibilidades. –

1

Solo una nota al pie .. Por alguna razón esto funciona en VB.

Parece que la implementación del preprocesador en C# y VB difiere cuando trato de convertir el Methodgroup/adderessof a un delegado.

Cuestiones relacionadas