How do you get a variable's name as it was physically typed in its declaration? [duplicate]
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
The class below contains the field city.
I need to dynamically determine the field's name as it is typed in the class declaration i.e. I need to get the string "city" from an instance of the object city.
I have tried to do this by examining its Type in DoSomething() but can't find it when examining the contents of the Type in the debugger.
Is it possible?
public class Person
{
public string city = "New York";
public Person()
{
}
public void DoSomething()
{
Type t = city.GetType();
string field_name = t.SomeUnkownFunction();
//would return the string "city" if it existed!
}
}
Some people in their answers below have asked me why I want to do this. Here's why.
In my real world situation, there is a custom attribute above city.
[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";
I need this attribute in other code. To get the attribute, I use reflection. And in the reflection code I need to type the string "city"
MyCustomAttribute attr;
Type t = typeof(Person);
foreach (FieldInfo field in t.GetFields())
{
if (field.Name == "city")
{
//do stuff when we find the field that has the attribute we need
}
}
Now this isn't type safe. If I changed the variable "city" to "workCity" in my field declaration in Person this line would fail unless I knew to update the string
if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}
So I am trying to find some way to pass the string to this code without physically typing it.
Yes, I could declare it as a string constant in Person (or something like that) but that would still be typing it twice.
Phew! That was tough to explain!!
Thanks
Thanks to all who answered this * a lot*. It sent me on a new path to better understand lambda expressions. And it created a new question.
Solution 1:
Maybe you need this. Works fine.
I found this here.
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);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
Output will be:
Name is: 'domain' Value is: 'matrix'
Solution 2:
I know this is old question, but I was trying to achieve the same and google sent me here. After many hours I finally found a way. I hope somebody else will find this useful.
There are actually more ways to accomplish this:
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
GetName3(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
static string GetName3<T>(Func<T> expr)
{
return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}
The first is fastest. The last 2 are approx 20 times slower than the 1st one.
http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
Solution 3:
city
in this case is an instance of type string
. When you call .GetType()
you return the actual string type, which has no knowledge at all of your particular city instance.
I'm having a hard time seeing why you can't just type "city" in the code as a string literal here, if that's what you need. Perhaps it would help if you shared what you want to use this value for and in what circumstances you will call your DoSomething()
function.
At the moment, my best guess is that what you really want to do is reflect the entire Person
class to get a list of the fields in that class:
public void DoSomething()
{
MemberInfo[] members = this.GetType().GetMembers();
// now you can do whatever you want with each of the members,
// including checking their .Name properties.
}
Okay, based on your edit I have some more for you.
You can find the name of fields that are decorated with your attribute at run-time like this:
Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
.Where(m =>
m.GetCustomAttributes(typeof(MyCustomAttribute)).Any() ) )
{
// "member" is a MemberInfo object for a Peson member that is
// decorated with your attribute
}
You can also use binding flags in the first GetMembers() call to limit it to just fields, if you want.
Solution 4:
You mentioned "i.e. I need to get the string "city" from an instance of the object city." Are you looking to get the field name from the value of the field. For example:If there are 2 Person object one with city "New York" and the other with city "London", are you looking for the function to return "city". Is this what you mean by dynamic?
With your current design you will always need to compare the name of the field from the FieldInfo against a string. What if you instead decouple this so that you hold the identifier to use for comparison purposes during reflection as part of the attribute. Something like this:
public enum ReflectionFields
{
CITY = 0,
STATE,
ZIP,
COUNTRY
}
[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
public ReflectionFields Field { get; private set; }
public string MiscInfo { get; private set; }
public CustomFieldAttr(ReflectionFields field, string miscInfo)
{
Field = field;
MiscInfo = miscInfo;
}
}
public class Person
{
[CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
public string _city = "New York";
public Person()
{
}
public Person(string city)
{
_city = city;
}
}
public static class AttributeReader<T> where T:class
{
public static void Read(T t)
{
//get all fields which have the "CustomFieldAttribute applied to it"
var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
if (attr.Field == ReflectionFields.CITY)
{
//You have the field and you know its the City,do whatever processing you need.
Console.WriteLine(field.Name);
}
}
}
}
public class Program
{
public static void Main(string[] args)
{
PPerson p1 = new PPerson("NewYork");
PPerson p2 = new PPerson("London");
AttributeReader<PPerson>.Read(p1);
AttributeReader<PPerson>.Read(p2);
}
}
You can now freely rename _city field of Person to something else and your calling code will still work since the code using reflection is trying to identify the field using the ReflectionFields enum value set as part of initialization of the attribute set on the field.
Solution 5:
Yes its possible !!!
Try this out...
public string DoSomething(object city)
{
return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
}