views:

159

answers:

3

So, let's say I have this code (VB.Net):

Sub Main()
   dim xxx as string = "HELLO WORLD"

   DetectName(xxx)

End Sub

Public Sub (theVariable as string)
   dim output as string = "The Value: {0} was stored in the variable named: {1}."
   debug.writeline(string.format(output, theVariable, What Goes Here????))
End Sub

Te output I want to see is:

The Value: HELLO WORLD was stored in the variable named: xxx.

Is this somehow possible, through reflection possibly?? (And if you definitively know it isn't possible, thats useful to know also).

In case you are wondering why I want to do this...I am trying to find some decent way to write a custom binding class (for forms, not grids) for asp.net because I can't seem to find anything that works well enough to be worth the trouble of using it. (NOTE: I am working with webforms and cannot use MVC to solve this problem).

I'm thinking my convention for supplying the binding information will be something like:
asp:TextBox id="myClassInstanceName.myPropertyName" ...

So, then I can have a function like so:

Public Sub Bind(webForm as System.Web.UI.Page, bindingObjects as HashTable)
   For each ctl in webForm.flattenedControls that contains "." within ID
      ' Here, which property is set would actually depends on control type
      ' magicGetValue() would find the property class instance within bindingObjects, which is indexed by variable *NAME* (not type), and then return the proper property value via reflection  
      ctl.Text = magicGetValue(ctl.ID, bindingObjects)
   End Sub
End Sub

Personally, I think this is a much easier syntax and much more powerful than the recommended asp:FormView, Bind("") approach. For example:
- if I want to implement the ability to render as read only, its quite a simple change in my underlying Bind function.
- if I want to have more than one class used to populate the UI, I can - if I want to traverse a rich domain model, I can, ie:
asp:TextBox id="_Customer.Address.State"

What I don't like is:
- relies upon reflection
- loosely typed (no compile time checking)
- I'd rather store the binding information somewhere other than ID, but don't know where else it could go within the aspx definition. Moving the binding declaration to the code behind would be better in some ways, but worse in others.

If anyone has any insight or advice, I'd be very grateful!

+3  A: 

It will definitely not work the way you want it, as local variable names are not even included in the assembly after it is compiled.

It might be possible if the variable is a field of a class (by passing a FieldInfo instead of the actual value or when the variable is passed ByRef).

mihi
Thanks, voted up for correct answer to first part of question.
tbone
This can be achieved indirectly by (ab)using anonymous types. See my answer for details.
LukeH
A: 

If I'm understanding what you're asking about, you shouldn't need to do what you're describing in the first part in order to accomplish what you say you're trying to do in the second part of your question. Since you can access the ID string of the textbox that gets created, you should be able to get the Property you're looking for by reflection:

PropertyDescriptor keyDescriptor = TypeDescriptor.GetProperties(dataItem).Find(keyPropertyName, false);
Key = keyDescriptor.GetValue(dataItem);

If you don't think this will work, can you clarify your question some more?

I agree with mihi, though, that you cannot discover the name of a variable that is local to the scope of a method.

StriplingWarrior
Actually, it was for a function accepting a paramarray of entities for the filling of the hashtable where I wanted to use this, I should have showed that code. I've wanted to be able to do this other times as well for some reason. Although now I know I can't do it, so thats good to know.
tbone
+2  A: 

You can't detect a variable's name directly, but you can workaround this by wrapping it in an anonymous type when passing it to the function.

You can then interrogate the anonymous type using reflection. The names of the type's properties will match the names of the original variables, thanks to name inferencing.

Sub Main()
    Dim xxx As String = "HELLO WORLD"
    Dim yyy As Integer = 42
    Dim zzz As DateTime = DateTime.Now

    DetectName(New With { xxx })
    DetectName(New With { yyy })
    DetectName(New With { zzz })

    ' or...
    ' DetectName(New With { xxx, yyy, zzz })
End Sub

Public Sub DetectName(Of T As Class)(test As T)
    Dim piArray As PropertyInfo() = GetType(T).GetProperties()

    Dim pi As PropertyInfo
    For Each pi In piArray
        Dim name As String = pi.Name
        Dim value As Object = pi.GetValue(test, Nothing)

        Dim output As String = _
            "The Value: {0} was stored in the variable named: {1}."
        Debug.WriteLine(String.Format(output, value, name))
    Next
End Sub

And, for completeness, here's the C# version:

void Main()
{
    string xxx = "HELLO WORLD";
    int yyy = 42;
    DateTime zzz = DateTime.Now;

    DetectName(new { xxx });
    DetectName(new { yyy });
    DetectName(new { zzz });

    // or..
    // DetectName(new { xxx, yyy, zzz });
}

public void DetectName<T>(T test) where T : class
{
    PropertyInfo[] piArray = typeof(T).GetProperties();

    foreach (PropertyInfo pi in piArray)
    {
        string name = pi.Name;
        object value = pi.GetValue(test, null);

        string output = "The Value: {0} was stored in the variable named: {1}.";
        Debug.WriteLine(string.Format(output, value, name));
    }
}
LukeH
cool, didn't know that syntax. Is this possible in C# as well?
mihi
@mihi: I've updated to include the C# version.
LukeH
Wow, very nice!!! (Changed correct answer to yours).So, whats your take on my idea of writing a custom databinder for ASP.Net?? This is a good implementation: http://www.west-wind.com/WebLog/posts/5468.aspx but, I want to be able to have the binding included within the html for the control itself, not in a seperate section. Have an opinion on this?
tbone