How to Find Out Variable or Parameter Name in C#?
Sometimes it might be useful to capture the name of the variable or parameter within the code to simplify error reporting or debugging.
I keep on encountering posts and comments saying that this is not possible in C#.
Well, it is not so. And there are multiple ways to do that.
Caveat. This was written in December 2008. A lot of things have changed in .NET Microsoft since then (so this code might not work as expected). I personally no longer use need this approach due to changes is development style. However, if you need something similar, you might be interested in Microsoft Code Contracts.
Anonymous class approach
Given the C# code:
static void Main(string[] args)
{
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Console.ReadLine();
}
The output would be:
Name is 'args'
Here's the C# code that does this:
static string GetName<T>(T item) where T : class
{
var properties = typeof(T).GetProperties();
Enforce.That(properties.Length == 1);
return properties[0].Name;
}
In the method above we use anonymous type declaration to capture name of the variable (thanks to the C# compiler features) and then use reflection to get the property name.
Performance is rather reasonable - 1000000 operations complete in 0,2 seconds. Still there is a trick to make code work even faster. It is called generic type caching:
static class Cache<T>
{
public static readonly string Name;
static Cache()
{
var properties = typeof(T).GetProperties();
Enforce.That(properties.Length == 1);
Name = properties[0].Name;
}
}
static string GetName<T>(T item) where T : class
{
return Cache<T>.Name;
}
As you can see, evaluation and reflection happen only once - when the we ask for the variable name for the first time. Every other call reuses the cached value.
This technique leverages specifics of static readonly members and could be applied to other scenarios, as well.
Expression approach
As it turns out, there is another, more simple approach to find out .NET variable name, that leverages the power of Linq Expressions:
static void Main(string[] args)
{
var domain = "matrix";
Check(() => domain);
Console.ReadLine();
}
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
}
By the way, this expression-based technique is called strongly-typed reflection, and it is a really handy tool in some situations.
It is quite flexible, too. Given the expression, we can get the name and the value of the variable. So you can do this as well:
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
The output will be:
Name is: 'domain'
Value is: 'matrix'
Note, that performance of this code (compared to the first approach) is a bit slower. With 1000000 operations it takes 3 seconds to get the name and 6 seconds to get the value. This might be or might not be an issue in your specific scenario.
I'm considering the second approach (just pulling the names) as the replacement for the name literals in the current declaration syntax of validation rules in the Shared Libraries:
Enforce.Argument(username, () => username,
StringIs.ValidEmail, StringIs.Limited(3,64));
Combining name and value in one expression is also really tempting, but I'd wait a bit to see if there is a way to statically cache compiled expressions.
Update: System.Reflection.Express from the Lokad Shared Libraries encapsulates methods for this kind of reflection.
IL Parsing
This approach is a bit more complex, but it does not have the performance problems of retrieving the parameter name.
We just need to replace our Check{K} method with this code snippet:
static void Check<T>(Func<T> expr)
{
// get IL code behind the delegate
var il = expr.Method.GetMethodBody().GetILAsByteArray();
// bytes 2-6 represent the field handle
var fieldHandle = BitConverter.ToInt32(il, 2);
// resolve the handle
var field = expr.Target.GetType()
.Module.ResolveField(fieldHandle);
Console.WriteLine("Name is: {0}", field.Name);
Console.WriteLine("Value is: {0}", expr());
}
Note that instead of dealing with the Linq Expressions (and the overhead of creating them), we leverage the delegates directly. This allows to drop the overhead of retrieving the original value by 300 times, compared to the expressions, making it negligible. Performance of the name retrieval stays the same (3-4 seconds per 1000000 operations).
There are more details on this approach in the How to Get Parameter Name and Argument Value From C# Lambda via IL?
Update: System.Reflection.Reflect from the Lokad Shared Libraries has some methods for this kind of reflection.
You can subscribe to the RSS feed of this blog, if you are interested in more updates on this topic.
Rinat Abdullin
The post on Development Compromises Around Lambda Expressions expands a bit on the development implications of using this approach.
Reader Comments (22)
Excellent, and very creative.
Now, can you extend it so it can be used inside a different method?
Say you have a method EnsureNotNull() as part of maintaining your design contract (probably similar to your Enforce class, but I'm not certain). Now, at the minute you'd call it with something like:
DesignContract.EnsureNotNull (parameter1, "parameter1");
so that the parameter name could be specified in the exception. Now, I'd really rather remove that string parameter and keep the method call really simple (even if I have to really complicate the method itself) so that I'd just call:
DesignContract.EnsureNotNull (parameter1);
Your code is nearly there, but since it would run in the EnsureNotNull method, it gets the name of the parameter to that method, rather than the name of the variable one stack frame up.
I know I could just use something like:
DesignContract.EnsureNotNull (parameter1, ContractParameter.GetName (new {parameter1}));
but that looks like a lot of complicated duplication in every call.
So, any creative ideas on how to get this to work?
Many thanks,
Geoff
I'm too lazy to test but would this code hit the cache for the second writeline?
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Is the compiler smart enough to use the same anonymous type for both calls?
Bill,
yes, it does. That is required by Linq.
Geoff,
my closest bet is DesignContract.EnsureNotNull (() =>parameter1);
Check out the article update.
Hello, Rinat.
Really interesting series of posts.
Thanks.
do you have any solution for C# 2.0 ?
i am using vs 2005 right not , , your solution is valid only for C# 3.0
Siraj,
The solution is valid for C# 3.0, indeed. But you can still target .NET 2.0 with it. Check out this post for details.
ya , but you still need VS2008 , do you have any thing for VS 2005 with .net 2.0 ?
just tell me alternative to " new {args} " in C# 2.0 ;
Siraj, there is not any reasonable alternative in VS 2005.
thanks any way i am really greatfull !
Why do you use
var properties = typeof(T).GetProperties();Enforce.That(properties.Length == 1);
Name = properties[0].Name;
instead of
Name = typeof(T).Name;?
And why
((FieldInfo)body.Member).GetValue(((ConstantExpression)body.Expression).Value)
instead of
expr.Compile()()?
Im sure you have some reason, I'm just not very experienced with this stuff, and is pretty curious... want to learn :p
1. Because "f__AnonymousType0`1" is not the name we are looking for.
2. Performance is much better.
People deserve very good life and personal loans or just collateral loan would make it better. Just because people's freedom is grounded on money.
static string GetParameterName(int parameterIndex)
{
var frame = new StackFrame(1);
var method = frame.GetMethod();
var parameter = method.GetParameters()[parameterIndex];
return parameter.Name;
}
This works only for "current" method, where you call GetParameterName method. For deeper calls you should change StackFrame constructor's parameter.
Just tested the performance and as of 22.6.2011 (VS 2010, .NET 4.0), expression approach (((MemberExpression)expression.Body).Member.Name) is about two times faster than IL parsing for 10 000 000 iterations.
Hi, the first approach does not work in every case to me (. NET 4.0 and VS2010) and others never return to the original name of the variable. I mean:
myClass
{
string Name = "Alberto";
...
void foo(object obj)
{
MessageBox.show("Field: \"" + GetName(obj) + "\" - Value: \"" + obj.ToString() + "\"");
}
Always print
Field: "obj" - Value: "Alberto"
instead of
Field: "Name" - Value: "Alberto"
What am I doing wrong?
Alberto, this post was written in December 2008. A lot of things have changed in .NET Microsoft since then (so this code might not work as expected). I personally no longer use need this approach due to changes is development style. However, if you need something similar, you might be interested in Microsoft Code Contracts.
Best regards,
Rinat
hey Rinat
Sorry for asking a silly question. In which namespace is the class 'Enforce' found? I'm referring to the Anonymous class approach.
Thanks
Yosief,
The code can probably be found in old sources of Lokad Shared libraries on github (Lokad namespace)
However, I don't recommend to use that code any longer. If you need enforcement, Microsoft Code Contracts might be a better options.