2012-03-04 14 views
6

¿Cómo obtengo el nombre de propiedad de la propiedad en ejecución? Si la propiedad usa "return", entonces MethodBase.GetCurrentMethod(). Name devuelve el nombre de la propiedad. Pero cuando uso "yield return" MethodBase.GetCurrentMethod(). Name devuelve "MoveNext". ¿Cómo obtengo el nombre de la propiedad de ejecución cuando utiliza el retorno de rendimiento?Cómo obtener el nombre de la propiedad cuando usa rendimiento return

Código de ejemplo

class Program 
    { 
     static void Main(string[] args) 
     { 

     var x = myProgram.Something; 

     Console.ReadLine(); 
     }  
    } 

public class myProgram 
{ 
    public static IEnumerable<string> Something 
    { 
     get 
     { 
      string var = MethodBase.GetCurrentMethod().Name; 
      for (int i = 0; i < 5; i++) 
      { 
       yield return var; 
      } 
     } 
    } 
} 
+4

¿Cuál es el caso de uso? Si entendimos la necesidad y el contexto, probablemente podríamos ayudarlo mejor. – jason

+1

¿Qué estás tratando de lograr? – Lloyd

+0

@Jason, podría pensar en algunos casos de uso, solo uno de los cuales sería iniciar sesión. Es una buena pregunta – kelloti

Respuesta

5

Como te habrás dado cuenta, el compilador reorganiza cómo el los métodos funcionan y Algo devuelve una clase privada que implementa IEnumerable. Como tal, los contenidos reales de su método aparecen en el método MoveNext de esta clase privada, por lo que MethodBase.GetCurrentMethod no devuelve lo que parece que debería devolver.

Ocurre que el nombre de la clase privada se deriva del nombre del método original, que en este caso es <Enumerate>d__0. Por lo tanto, puede analizar el nombre del método original desde un marco de pila.

static IEnumerable<string> Enumerate() 
{ 
    var method = new StackTrace(true).GetFrame(0).GetMethod().DeclaringType.Name; 
    yield return Regex.Replace(method, @".*<([^)]+)>.*", "$1"); 
} 

static void Main(string[] args) 
{ 
    foreach (var @string in Enumerate()) 
    { 
     Console.WriteLine(@string); 
    } 
} 

Esto es, por supuesto, un corte fácil y no podía trabajar en futuras versiones de .NET

+0

El nombre no está realmente ofuscado.La ofuscación intenta intencionalmente ocultar lo que hace el código, lo que no ocurre aquí. Los nombres como este se llaman "indescriptibles" porque no son nombres de C# válidos. Además, no es necesario usar 'StackTrace' aquí,' MethodBase.GetCurrentMethod() 'es suficiente. – svick

+0

@svick supongo su derecha, lo edité – kelloti

+0

Gracias por la ayuda voy con enfoque StackTrace por ahora sabiendo que es un truco. – kumar

1

me movería el iterador en un método de ayuda:

public class myProgram 
{ 
    public static IEnumerable<string> Something 
    { 
     get 
     { 
      string var = MethodBase.GetCurrentMethod().Name; 
      return GetSomethingInternal(); 
     } 
    } 

    private static IEnumerable<string> GetSomethingInternal() 
    { 
     for (int i = 0; i < 5; i++) 
     { 
      yield return i; 
     } 
    } 
} 
5

Como es fácil adivinar, el problema aquí es que una declaración yield return hace un poco de reescritura detrás las escenas, similar a cómo lo hace una expresión using o lambda. En realidad se implementa como un enumerador, con el código que llama al yield return como parte del método MoveNext en el enumerador.

Este es un problema global de la utilización Reflexión: te da tiempo de ejecución información sobre su código de ejecución, que puede no coincidir con su tiempo de compilación idea de lo que era ese código.

Esa es una manera larga de decir que no hay una manera fácil de obtener la información que desea. Si fuera a mover el yield return a otro método, entonces cualquier código que no pertenezca a ese método no formará parte del MoveNext, pero puede que no logre lo que necesita. Ya no está obteniendo el nombre del método que está ejecutando el yield return, recibe el nombre de la persona que llama. Si eso es todo lo que importa, que se ve así:

public IEnumerable<string> Something 
{ 
    get 
    { 
     var x = MethodBase.GetCurrentMethod().Name; 
     return this.DoSomething(x); 
    } 
} 

private IEnumerable<string> DoSomething(string x) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     yield return x; 
    } 
} 

EDIT: Aunque dudo que le ayudará en el corto plazo, para el registro, este problema también se resuelve al usar nuevos atributos de C# 5. Desde el atributo CallerMemberName se resuelve en tiempo de compilación, y al parecer antes de que el iterador se ha reescrito en una clase de enumerador, se produce el nombre de la propiedad:

public IEnumerable<string> Something 
{ 
    get 
    { 
     var x = this.GetCallerName(); 
     for (int i = 0; i < 5; i++) 
     { 
      yield return x; 
     } 
    } 
} 

private string GetCallerName([CallerMemberName] string caller = null) 
{ 
    return caller; 
} 
+0

Gracias por la información estará atento a CallerMemberName. debido a otras limitaciones voy con la solución StackTrace. – kumar

Cuestiones relacionadas