4

Is is possible to get the name of property that the current class is assigned to in the class it was called from?

Let's say I've got three classes:

class Parent1
{
   public Child myName;

   public void Foo()
   {
      myName.Method();
   }
}

class Parent2
{
   public Child mySecondName;

   public void Foo()
   {
      mySecondName.Method();
   }
}

class Child
{
   public void Method()
   {
      Log(__propertyName__);
   }
}

I'd like to Log the value myName when the Method is called from Parent1 and mySecondName if the Method is called from Parent2.

Is it possible using reflection and not by passing names by string in argument (I want to use it only for the debugging purposes, I don't want to link those class together in any way)

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Adassko
  • 5,201
  • 20
  • 37
  • You can't do it via reflection, however, you can do it using [expression trees](http://stackoverflow.com/questions/72121/finding-the-variable-name-passed-to-a-function-in-c-sharp) – James Sep 26 '13 at 08:19
  • @James that may work for parameters supplied to a method - in this case, the OP wants the name of the variable that contains the reference to the class being invoked. Would that still be possible using expression trees? – C.Evenhuis Sep 26 '13 at 08:25
  • @C.Evenhuis probably not directly but you could have a `Log` method which took in the variable name - good example [here](http://stackoverflow.com/questions/2566101/how-to-get-variable-name-using-reflection). – James Sep 26 '13 at 08:31
  • @James inside Method(), `this` equals the value of the variable - I'm trying to change my example using the links you provide but they all require supplying the variable. – C.Evenhuis Sep 26 '13 at 08:35
  • 1
    @C.Evenhuis yeah and what that does is raise questions about the design to start with. The OP wants to log the variable name of `this` as it's declared in `Parent1` - that concept is flawed IMO. `Parent1` should be the logger, not the `Child`. – James Sep 26 '13 at 08:43
  • @James: I'm just trying to find one bug in application and this is temporary. There's simply too many places to place the logger if I'd like to do it from the other side – Adassko Sep 26 '13 at 10:01

3 Answers3

3

Using the StackTrace you can at least get the method and class from which the call was made:

System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace();
Type calledFromType = trace.GetFrame(1).GetMethod().ReflectedType;

This should give you the Parent1 type.

I don't think there is a way to get the name of the variable with which the method was invoked.

You could of course enumerate all fields and properties of calledFromType and see if one of them is of the Child type, but you won't get a guarantee that field or property was actually used when invoking.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
  • 1
    Please note, that 1) using StackTrace is very expensive, and 2) depending on your build (DEBUG/RELEASE) you will miss things due to optimalizations by the compiler. http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx. – Maarten Sep 26 '13 at 08:31
3

There is no realistic way to do this using reflection, for a variety of reasons:

  1. There is nothing in the state of your instance that is related to a specific 'owner'.

  2. Your code can be called from anywhere that has access to the property, so a stack trace won't reliably return anything useful.

  3. A reference to your class' instance can be stored in any number of places, including variables and parameters to method calls.

So basically, no. The best you can do is tell it where it is, and even then you fall foul of reference copies.

Corey
  • 15,524
  • 2
  • 35
  • 68
2
class Child
    {
        public void Method()
        {
            StackFrame sf = new StackFrame(1);
            var type = sf.GetMethod().ReflectedType;

            var field = type.GetFields().FirstOrDefault(i => i.FieldType == typeof(Child));

            Log(field.Name);
        }
    }
Lev
  • 3,719
  • 6
  • 41
  • 56
  • Please note, that 1) using StackFrame is very expensive, and 2) depending on your build (DEBUG/RELEASE) you will miss things due to optimalizations by the compiler. See http://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.aspx. – Maarten Sep 26 '13 at 08:32
  • You have no guarantee that that field was used for the call. In `Parent1`, he could call `new Parent2().mySecondName.Method()` and your code would return "myFirstName". – C.Evenhuis Sep 26 '13 at 08:32
  • Agree with both comments, of course this is not a general solution of problem – Lev Sep 26 '13 at 08:51