2012-03-18 9 views
6

Estoy tratando de escribir una función que toma una función como uno de sus argumentos, una tarea que he hecho muchas veces antes. Esto funciona bien:La función de una función funciona en una dirección, no en la otra

int RunFunction(Func<int,int> f, int input) { 
    return f(input); 
} 
int Double(int x) { 
    return x*2; 
} 

// somewhere else in code 
RunFunction(Double,5); 

embargo, esto no funciona:

public static class FunctionyStuff { 
    public static int RunFunction(this Func<int,int> f, int input) { 
     return f(input); 
    } 
} 

// somewhere else in code 
Double.RunFunction(5); 

Cualquier idea de por qué funciona la primera y la segunda no lo hace?

Respuesta

5

La primera versión está realizando una conversión de grupo de método como parte de la coincidencia de "argumento para parámetro". Esta conversión no ocurre para los métodos de extensión. Lo mismo es cierto para las expresiones lambda: no se puede escribir:

((int x) = > x * 2).RunFunction(10); 

tampoco.

La sección 7.6.5.2 de la especificación C# 4 proporciona detalles de las invocaciones al método de extensión. Comienza al exigir que la invocación del método es de una de estas formas:

expr.identifier () 
expr.identifier (args) 
expr.identifier <typeargs> () 
expr.identifier <typeargs> (args) 

El tipo de la expresión (expr) se utiliza a continuación en esta regla: método

Una extensión C i .M jes elegible si

  • [...]
  • Una identidad, referencia, o la conversión de boxeo implícita existe desde expr con el tipo del primer parámetro de M j.

La versión comentada de la especificación a continuación, incluye el siguiente comentario de Eric Lippert:

Esta regla asegura que hacer un método que se extiende double no se extienda también int. También asegura que no se definan métodos de extensión en funciones anónimas o grupos de métodos.

+0

Quizás también deba explicar * why * no ocurre con los métodos de extensión y las expresiones lambda. Es porque no tienen un tipo de delegado específico. 'Func ' y un hipotético 'MyIntIntDelegate' podría tener la misma firma, pero serían diferentes tipos, por lo que el compilador no podría saber a cuál convertir. – Timwi

+0

Entonces, si estoy haciendo esto bien, en la primera versión hay un elenco implícito de 'Método' a' Func'? – Joe

+0

@Timwi: Estaba llegando allí ... –

0

Extension Methods "se llaman como si fueran métodos de instancia en el tipo extendido".

En su caso Double no es una instancia, por lo que no puede llamar al método de extensión.

Cuestiones relacionadas