2011-03-19 10 views
19

¿Es posible obtener un nombre de método de una acción? Sé que siempre podría pasar una cadena, pero esperaba algo un poco más inteligente.Obtener el nombre del método de la acción

public bool DeviceCommand(Action apiCall) 
    { 
     //It would be nice to log the method name that was passed in 
     try 
     { 
      apiCall(); 
     } 
     catch (Exception exc) 
     { 
      LogException(exc); 
      return false; 
     }   

     return true; 
    } 

uso es el siguiente:

void MyMethod() 
(
    DeviceCommand(() => api.WriteConfig(config)); 
) 
+2

Esa es una expresión LINQ, ¿qué crees que debería denunciarse? ¿Qué debería ser si fuera 'DeviceCommand (() => (estándar? Api.WriteConfig (config): api.WriteExtendedConfig (config)));' – tvanfosson

+0

¿Está diciendo que es imposible lograr lo que quiero sin pasar algún tipo de orden? de parámetro porque es una expresión LINQ? – Robert

+1

no, solo indica que solo porque su ejemplo es simple, el problema general no es porque Acción podría ser una variedad de cosas, incluyendo cualquier bloque de código calificado. Probablemente estaría bien si no registro la llamada, sino que simplemente me aseguro de incluir el seguimiento de la pila si hay una excepción. O simplemente registre la llamada en cada método si desea realizar un seguimiento de las llamadas. – tvanfosson

Respuesta

18

Si sus invocaciones de DeviceCommand son siempre va a ser de la forma

DeviceCommand(() => someObject.SomeMethod(parameters)); 

entonces se podría modificar DeviceCommand tomar un árbol de expresión como un parámetro. Esto le permitiría a profundizar en el árbol para obtener la información que desea (en este caso, la cadena "SomeMethod"), a continuación, compilar el árbol en un delegado y ejecutarlo:

public bool DeviceCommand(Expression<Action> apiCallExp) 
{ 
    var methodCallExp = (MethodCallExpression) apiCallExp.Body; 
    string methodName = methodCallExp.Method.Name; 
    // do whatever you want with methodName 

    Action apiCall = apiCallExp.Compile(); 
    try 
    { 
     apiCall(); 
    } 
    catch(Exception exc) 
    { 
     LogException(exc); 
     return false; 
    } 

    return true; 
} 

Por supuesto, la construcción y compilar un árbol de expresiones cada vez podría ser un problema de rendimiento importante (o no, solo depende de la frecuencia con que se llame a DeviceCommand). Tendrás que decidir si las implicaciones de rendimiento (y la "piratería" general de este enfoque) valen la pena en tu situación.

15

Si se encuentra: Action.Method.Name

Sin embargo, esto sólo funciona si se pasa en el parámetro de acción como grupo método, no como una expresión lambda :

class Program 
{ 
    static void SomeActionName(){} 

    static void Main(string[] args) 
    { 
     LogMethodName(() => SomeActionName()); // <Main>b__0 
     LogMethodName(SomeActionName); // SomeActionName 

     var instance = new SomeClass(); 
     LogMethodName(() => instance.SomeClassMethod());; // <Main>b__1 
     LogMethodName(instance.SomeClassMethod); // SomeClassMethod 


    } 

    private static void LogMethodName(Action action) 
    { 
     Console.WriteLine(action.Method.Name); 
    } 
} 

class SomeClass 
{ 
    public void SomeClassMethod(){} 
} 
+0

Action.Method.Name devuelve el nombre del método anónimo del método en el que se encuentra DeviceCommand(), no la llamada api real. Por ejemplo, Action.Method.Name devuelve MyMethod en lugar de WriteConfig. Actualicé mi uso de ejemplo para mostrar esto. – Robert

+0

@ Aaron, @Robert: Acabo de probar esto, solo funciona si pasa el parámetro Action como un 'grupo de métodos', no como una expresión lambda. Para este último, necesita el enfoque de Aarons para pasar una 'Expresión' – jeroenh

Cuestiones relacionadas