1

I have two classes as follow:

First one:

class Class1
 {
     private void Method1()
      {
          var obj=new TestClass();
          obj.TestMethod1();
      }
 }

Second One:

class TestClass
 {
     public void TestMethod1()
      {
           TestMethod2();
      }

      private void TestMethod2()
       {
           //get the calling class 
       }
 }

When Class1.Method1 calls TestClass.TestMethod1 which in turn calls TestClass.TestMethod2, I want to get the fully qualified class name of Class1 inside TestClass.TestMethod2. I have seen this link, but I think I will get TestClass.TestMethod1 as method name and TestClass as the class name. How can I get the calling class name?

Community
  • 1
  • 1
Victor Mukherjee
  • 10,487
  • 16
  • 54
  • 97

4 Answers4

7

There is no nice way to do that. You can access the stack-frames (just look at the second frame, rather than the first) - but that is expensive and brittle. You could use optional caller-member-name attributes (being explicit from TestMethod1) to get hold of "Method1", but not the "Class1" part. One other option would be to pass in an object (or just the name) explicitly; for example:

  private void Method1()
  {
      var obj=new TestClass();
      obj.TestMethod1(this);
  }
  public void TestMethod1(object caller=null,
             [CallerMemberName] string callerName=null)
  {
       TestMethod2(caller??this,callerName??"TestMethod1");
  }

  private void TestMethod2(object caller=null,
             [CallerMemberName] string callerName=null)
  {
      string callerName = ((caller??this).GetType().Name) + "." + callerName
      //get the calling class 
  }

but I have to confess that is pretty ugly

Perhaps better would be to question why you need this in the first place.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Actually my TestClass is a utility class used by different other classes. I want to log any exception occuring in this TestClass inside the log file for its calling class. need to design it the other way around as you suggested. – Victor Mukherjee Jun 12 '13 at 09:01
1

Could you not pass the type into the second class via constructor like:

class Class1
{
    private void Method1()
    {
        Type t = typeof(Class1);
        var obj = new TestClass(t);
        obj.TestMethod1();
    }
}

class TestClass
{
    private Type _caller;

    public TestClass(Type type)
    {
        _caller = type;
    }
    public void TestMethod1()
    {
        TestMethod2();
    }

    private void TestMethod2()
    {
        //Do something with the class
    }
}
DGibbs
  • 14,316
  • 7
  • 44
  • 83
0

You might check out this code to find your solution without having to pass class instances or type parameters, etc....:

class Program
{
    static void Main(string[] args)
    {
        var c = new Class1();
        c.Method1();
    }
}

class Class1
{
    public void Method1()
    {
        var obj = new TestClass();
        obj.TestMethod1();
    }
}

class TestClass
{
    public void TestMethod1()
    {
        TestMethod2();
        var mth = new StackTrace().GetFrame(1).GetMethod();
        var clss = mth.ReflectedType.Name;
        Console.WriteLine("Classname in Method1(): {0}", clss);
    }

    private void TestMethod2()
    {
        //get the calling class 
        var mth = new StackTrace().GetFrame(1).GetMethod();
        var clss = mth.ReflectedType.Name;
        Console.WriteLine("Class in .Method2(): {0}", clss);
    }
}
bbqchickenrobot
  • 3,592
  • 3
  • 45
  • 67
  • 1
    `StackTrace` is very expensive. This works but is almost twice as slow as passing in the `Type` and the intention of it's use is not as clear. Benchmarked at: 0.92003311 ms vs 0.0501211ms over 1000000 iterations. – DGibbs Jun 12 '13 at 09:14
  • Lets be honest, it is another method and a lot cleaner than cluttering method signatures with attributes or type params IMO. Readibilty at the cost of perf, but don't think the perf is that big to cause an issue. In any case, it does answer the question and shows yet another way of accomplish the same task. – bbqchickenrobot Jun 12 '13 at 17:49
  • I'd strongly disagree that this is more readable, but yes it does work. I wouldn't say that a single constructor that takes a type constitutes 'clutter' either, in fact i'd go as far as to say that its intention is far more clear than in this example. Lets just agree to disagree :) – DGibbs Jun 13 '13 at 08:54
  • haha, ya, right when I read "I'd strong disagree..." I thought, hmm... readability can be kind of an opinion type thing. So, agreed :) You make a good case :) – bbqchickenrobot Jun 13 '13 at 14:25
0

This will get the Type that first called TestClass. It prints:

TestStack.Class1
TestStack.Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace TestStack
{
    class Class1
    {
        public void Method1()
        {
            var obj = new TestClass();
            obj.TestMethod1();
        }
    }

    class TestClass
    {
        public void TestMethod1()
        {
            TestMethod2();
        }

        private void TestMethod2()
        {
            StackTrace st = new StackTrace();
            Type calling = null;
            foreach (var sf in st.GetFrames())
            {
                var type = sf.GetMethod().DeclaringType;
                if (type != this.GetType())
                {
                    calling = type;
                    break;
                }
            }
            Console.WriteLine(calling);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1();
            class1.Method1();
            TestClass testClass = new TestClass();
            testClass.TestMethod1();
        }
    }
}
Ahmed KRAIEM
  • 10,267
  • 4
  • 30
  • 33