2012-03-07 11 views
13

Tengo dos métodos de extensión en IDataReader con las siguientes firmas:la conversión de un grupo método de extensión a un delegado con un tipo genérico

internal static List<T> GetList<T>(this IDataReader reader, Func<string, T> del) 

internal static double? GetDoubleOrNull(this IDataReader reader, string columnName) 

GetDoubleOrNull todavía no tiene ninguna sobrecargas.

Por otra parte, yo soy capaz de hacer

Func<string, double?> del = reader.GetDoubleOrNull; 

var x = reader.GetList(del); 

o

var x = reader.GetList<double?>(reader.GetDoubleOrNull); 

o simplemente pasar de un método de instancia como

public double? blah(string s) 

var x = reader.GetList(blah); 

pero no puedo hacer

var x = reader.GetList(reader.GetDoubleOrNull); 

El compilador da el error

cannot convert from 'method group' to 'System.Func<string,double?>' 

No entiendo esto. Pensé que ya que no hay sobrecarga en GetDoubleOrNull, no habría una resolución de sobrecarga y podría inferir el parámetro de tipo de la firma del método.

La parte realmente confusa es cómo parece funcionar al pasar en blah.

+3

Muy interesante. Un lanzamiento explícito '' var x = reader.GetList ((Func ) Lector.GetDoubleOrNull) '' también funciona. Resharper marca el lanzamiento como redundante, pero sin él la compilación falla. ¿Está Jon Skeet cerca? –

+3

¿Hay alguna manera de invocar a Jon Skeet (o tal vez a Eric Lippert)? ¿Dicen su nombre tres veces o algo así? – Chris

+1

relacionado: http://stackoverflow.com/questions/7745852/method-inference-does-not-work-with-method-group y http://stackoverflow.com/questions/2057146/compiler-ambiguous-invocation-error -anonymous-method-and-method-group-with-fun – AakashM

Respuesta

0

GetDoubleOrNull devuelve un doble? GetList espera un System.Func<string,int?> un

El mensaje de error IDataReader y es un poco engañosa

doble pública? bla (s)

var x = reader.GetList (blah);

blah es un delegado en esta llamada. En GetList (GetDoubleOrNull) es el resultado de obtener doubleOrNull.

Buena pregunta sin embargo. Publique la respuesta independientemente de si he ayudado o no.

+0

El '' int'' debe ser un error tipográfico, cambiarlo a '' double'' aún da el error del compilador. –

+0

Jacek es correcto. Mi error. Lo siento. – Moss

+1

Usted dijo "En GetList (GetDoubleOrNull) es el resultado de obtener doubleOrNull", pero esto no es correcto. En este caso, 'GetDoubleOrNull' no está siendo evaluado, se trata como un grupo de métodos. – Chris

8

Prefacio: Pase a la edición si quiere la explicación completa. Spoiler: Los métodos de extensión son un truco de compilación, y en realidad tienen un argumento más de lo que parecen cuando los invocas.

Está en la resolución del grupo de métodos. Aparentemente, el compilador de C# no se toma el tiempo para determinar si el método que está utilizando tiene sobrecargas o no; solo siempre requiere un lanzamiento explícito. Salida:

What is a method group in C#?
Method Inference does not work with method group

El grupo método que regresa de reader.GetDoubleOrNull se estrecha por lo que intenta convertir a: GetDoubleOrNull podría referirse a cualquier número de métodos sobrecargados con ese nombre. Debes lanzarlo explícitamente.

Curiosamente, ni siquiera se puede asignar un grupo de método a una variable de tipo implícitamente por la misma razón:

var x = reader.GetDoubleOrNull; 

falla al compilar, ya que requiere una conversión explícita.

Editar estoy bastante seguro de que la confusión en este punto tiene que ver con los métodos de extensión:

Mira la siguiente clase de prueba:

public static class Extensions 
{ 
    public static List<T> GetList<T>(this IDataReader reader, Func<string, T> del) 
    { 
     throw new NotImplementedException(); 
    } 

    public static double? GetDoubleOrNull(this IDataReader reader, string columnName) 
    { 
     throw new NotImplementedException(); 
    } 

    public static double? blah(this string s) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Se puede llamar con éxito

var x = reader.GetList(Extensions.blah); 

¿Por qué podría ser? blah es también un método de extensión estático, por lo tanto, según su evidencia, parecería que la línea anterior no debe compilarse. Para complicar aún más las cosas, vamos a añadir este método:

public static List<T> GetList2<T>(this IDataReader reader, Func<IDataReader, string, T> del) 
{ 
    throw new NotImplementedException(); 
} 

Ahora puede llamar

x = reader.GetList2(Extensions.GetDoubleOrNull); 

y se compilará correctamente. ¿Lo que da?

Aquí está la respuesta: Los métodos de extensión no realmente agregan métodos a sus objetos. Son realmente un truco de compilación para permitirle programar como si esos métodos fueran parte de sus clases. De here:

En su código se invoca el método de extensión con el método de instancia sintaxis . Sin embargo, el lenguaje intermedio (IL) generado por el compilador traduce su código en una llamada en el método estático. Por lo tanto, el principio de encapsulación no se está violando realmente . De hecho, los métodos de extensión no pueden acceder a las variables privadas en el tipo que se están extendiendo.

Por lo tanto, cuando se llama

var x = reader.GetDoubleOrNull("myColumnName"); 

lo que realmente se compila y se ejecuta es esencialmente esto (una llamada perfectamente legítimo, aunque es un método de extensión):

var x = Extensions.GetDoubleOrNull(reader, "myColumnName"); 

Así , cuando intente utilizar GetDoubleOrNull como arg para Func<string, double?>, el compilador indica "Puedo convertir GetDoubleOrNull en Func<IDataReader, string, double?> porque tiene dos argumentos, pero no k ahora la forma de convertirlo en un Func<string, double?> "

A pesar de que está llamando como si se trata de un método de instancia de la IDataReader con una arg, no es: esto es sólo un método estático con dos argumentos que el C# el compilador te ha engañado para que pienses que es parte de IDataReader.

+0

Excelente respuesta e investigación. Quiero +1 de nuevo. ;-) – Chris

+3

No soy Jon Skeet, pero hago lo que puedo: D – eouw0o83hf

+0

Gracias por su respuesta. Lamentablemente, todavía no parece entender el problema con claridad. La primera pregunta que ha mencionado es de la que tengo conocimiento. Leí el segundo, así como los publicados por AakashM, y me parece que se trata de cómo la resolución de sobrecarga no tiene en cuenta los tipos de devolución. Entiendo que. Pero, ¿cómo funciona el trabajo 'blah'? ¿No hay resolución de sobrecarga que tenga lugar en ese caso? ¿Si no, porque no? Si es así, ¿cómo es que tiene éxito? – Moss

Cuestiones relacionadas