How do i get property name of the executing property. If the property uses "return" then MethodBase.GetCurrentMethod().Name returns the name of the property. But when I use "yield return" MethodBase.GetCurrentMethod().Name returns "MoveNext". how do I get the executing property name when it uses yield return?
Sample Code
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;
}
}
}
}
As you've probably noticed, the compiler reorganizes how the methods work and Something returns a private class that implements IEnumerable
. As such, the actual contents of your method appear in the MoveNext
method of this private class, so MethodBase.GetCurrentMethod
doesn't return what it seems like it should return.
It happens that the name of the private class is derived from the original method name, which in this case is <Enumerate>d__0
. So, you can parse the original method name from a stack frame.
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);
}
}
This is, of course, a hack and could easily not work in future versions of .NET
As you can probably guess, the problem here is that a yield return
statement does a bit of rewriting behind the scenes, similar to how a using
or lambda expression does. It actually gets implemented as an enumerator, with the code that calls yield return
being part of the MoveNext
method on the enumerator.
This is an overall problem of using Reflection: it gives you runtime information about your executing code, which may not match your compile-time idea of what that code was.
That's a long-winded way of saying that there's no easy way to get the information you want. If you were to move the yield return
next into a separate method, then any code outside of that method would not be part of the MoveNext
, but that may or may not accomplish what you need. You are no longer actually getting the name of the method that is executing the yield return
, you are getting the name of it's caller. If that's all you care about, it looks like this:
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: While I doubt it will help you in the short term, for the record, this problem is also solved when using C# 5's new attributes. Since the CallerMemberName
attribute is resolved at compile time, and apparently before the iterator has been rewritten into an enumerator class, it produces the name of the property:
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With