views:

256

answers:

4

I am looking for a way to retrieve the variable name, so I don't have to use hard-coded declarations when needed (for property names etc.):

I hardly believe it's possible; maybe someone has a solution. Note: even not variables, properties would also be a move.

'Pseudo:
Module Module1

    Sub Main()
        Dim variable = "asdf"
        Dim contact As New Contact

        Dim v1 = GetVariableName(variable) 'returns variable
        Dim v2 = GetVariableName(contact.Name) 'returns Name

    End Sub

    Class Contact
        Public ReadOnly Property Name()
            Get
                Return Nothing
            End Get
        End Property
    End Class

    Public Function GetVariableName(variable As Object) As String
        ':}
    End Function

End Module

Answers are welcommed in either VB or C#.

+3  A: 

Rinat Abdullin is doing something like this by parsing IL from an anonymous method (or lambda expression). His full code is here.

So, your example would look like:

class Program
{
 static void Main (string[] args)
 {
  var variable = "asdf";

  var v1 = GetVariableName(() => variable);  // returns "variable"
 }

 static string GetVariableName (Func<object> variable)
 { // Again, credit to Mr. Abdullin ...
  var il = variable.Method.GetMethodBody().GetILAsByteArray();
  var fieldHandle = BitConverter.ToInt32(il,2);
  var field = variable.Target.GetType()
    .Module.ResolveField(fieldHandle);
  return field.Name;
 }
}

However, this does not directly extend to your second case (contact.Name --> "Name").

Abraham Pinzur
there is a simpler solution with expression trees, and it seems like what you've done, see my response
Nicolas Dorier
+2  A: 

That's not possible. What's sent to the method in your example is not the variable itself, but only a copy of the reference that the variable contains.

The method could scan all objects that exist for the reference among member variables, but that would only be doable if the variable is a class member. Local variables are not possible to reach that way as they only exist on the stack. Also, if the same reference exist in more than one variable, the method would not be able to tell which of them was used.

In your example the Name property returns a null reference, it is of course impossible to tell where that came from.

If the variable was a value type, it would get boxed inside a new object on the heap. As the only reference to the boxed object is the one that is sent to the method, and the boxed object has no reference back to the original, there is no way of telling which variable was boxed.

Guffa
No that's possible, see my response, expression trees powaaaa!
Nicolas Dorier
@Slashene: Yes, if you completely change how the method is called. Something like in the OP is not possible.
Guffa
+3  A: 

@Abraham Pinzur; Following a further link in the article you linked to provides this snippet:

static void Main(string[] args)
{
Console.WriteLine("Name is '{0}'", GetName(new {args}));
Console.ReadLine();
}

static string GetName<T>(T item) where T : class
{
var properties = typeof(T).GetProperties();
return properties[0].Name;
}

Which does produce "Name is 'args'". Rinat's method exploits the property name generated by the C# compiler to produce an anonymous type in the expression new{args}. The full article is here: http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html

--Edit--

Having read further into Rinat's article, this can also be done by producing an expression tree and browsing either the tree, or the IL it contains. Basically, read the linked article!

FacticiusVir
I never thought using anonymous types for that, nice tips !
Nicolas Dorier
+1 That's cool!
Roman Boiko
+4  A: 

Oh there is a simple solution, use expression trees here is an example, just adapt to your needs in c#

string GetPropertyName<T>(Expression<Func<T>> property)
{
    MemberExpression ex = (MemberExpression)property.Body;
    string propertyName = ex.Member.Name;
    return propertyName;
}

Now you can do

String example = null;
String propertyName = GetPropertyName(()=>example.Length);
//propertyName == "Length"

The first time I've seen that, it was a revelation ! ;)

Nicolas Dorier
This is a great solution as well - probably not quite as fast as IL parsing, but perhaps more elegant (and less error-prone).
Abraham Pinzur
You are the man!I wouldn't believe it!!!
Shimmy