2012-03-04 4 views
6

실행중인 속성의 속성 이름을 어떻게 가져올 수 있습니까? 속성이 "return"을 사용하면 MethodBase.GetCurrentMethod(). Name은 속성의 이름을 반환합니다. 그러나 "yield return"을 사용하면 MethodBase.GetCurrentMethod(). Name이 "MoveNext"를 반환합니다. yield 반환 값을 사용할 때 실행 속성 이름을 얻으려면 어떻게해야합니까?수익률을 사용할 때 속성 이름을 얻는 방법

내가 도우미 메서드에 반복자를 이동 것

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

의 향후 버전에서 작동하지 않을 수 있을까? 우리가 필요와 맥락을 이해한다면, 우리는 아마도 당신을 더 잘 도울 수 있습니다. – jason

+1

달성하려는 것은 무엇입니까? – Lloyd

+0

@ Jason, 몇 가지 유스 케이스를 생각해 볼 수 있습니다. 좋은 질문입니다 – kelloti

답변

5

는, 컴파일러가 어떻게 재구성 다음 CallerMemberName 속성이 컴파일시에 해결되기 때문에 반복자의 열거 클래스로 다시 작성되었습니다 분명히 전에, 그것은 속성의 이름을 생성 메서드가 작동하고 Something이 IEnumerable을 구현하는 개인 클래스를 반환합니다. 따라서 메서드의 실제 내용은이 개인 클래스의 MoveNext 메서드에 표시되므로 MethodBase.GetCurrentMethod은 반환해야하는 것처럼 반환하지 않습니다.

개인 클래스의 이름은 원래 메서드 이름 (이 경우 <Enumerate>d__0)에서 파생됩니다. 따라서 스택 프레임에서 원래 메서드 이름을 구문 분석 할 수 있습니다.

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); 
    } 
} 

이것은 물론 해킹하고 쉽게 사용 사례 무엇 .NET

+0

이름은 실제로 난독 화되지 않았습니다.난독 화 (obfuscation)는 의도적으로 코드가하는 것을 숨기려고하는데, 여기서는 발생하지 않습니다. 이런 이름은 유효한 C# 이름이 아니기 때문에 "말할 수 없다"라고 불립니다. 또한 여기서는'StackTrace'를 사용할 필요가 없으며'MethodBase.GetCurrentMethod()'만으로 충분합니다. – svick

+0

@svick 나는 당신의 권리가 있다고 생각합니다. 나는 그것을 편집했습니다. – kelloti

+0

도움을 주셔서 감사합니다. 이제 stacktrace 접근 방식으로 해킹임을 알게 될 것입니다. – kumar

1

샘플 코드 : 당신은 아마 추측 수 있듯이

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

, 문제는 여기에 yield return 문 뒤에 재 작성을 조금 않는다는 것입니다 씬은 using 또는 람다 표현식이하는 것과 유사합니다. 실제로는 열거 자로 구현되고 yield return이라는 코드는 열거 자에서 MoveNext 메서드의 일부입니다.

이 반사를 사용하는 전반적인 문제이다 : 그것은 당신에게 당신의 컴파일시 그 코드가 무엇의 생각과 일치하지 않을 수 있습니다 귀하의 실행 코드에 대한 런타임 정보를 제공합니다.

원하는 정보를 쉽게 얻을 수 없다는 말은 오래 가지 않습니다. yield return을 별도의 메소드로 옮기려면 해당 메소드 외부의 코드는 MoveNext의 일부가 아니지만 필요한 코드가 될 수도 있고 아닐 수도 있습니다. 실제로 더 이상 yield return을 실행하는 메서드의 이름을 얻지 못하면 호출자의 이름을 얻게됩니다. 그게 당신이 걱정하는 모든의 경우는 다음과 같습니다

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; 
    } 
} 

편집 : 나는 기록을 위해, 단기간에 도움이 될 것입니다 의심하지만 C# 5의 새로운 속성을 사용하는 경우,이 문제는 해결된다.

당신은 아마 눈치 챘으로
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

정보 주셔서 감사합니다 CallerMemberName에 대한 감시. 다른 제약 때문에 StackTrace 솔루션을 사용할 것입니다. – kumar

관련 문제