CJC
CJC

Reputation: 817

Is it possible to determine which instance of a class the current instance of a class is instantiated from?

As the title suggests, it is possible to determine which instance of a class a particular instance of another class is instantiated from?

Update: Example Code below

class FooBar: Foo
{
    private Context context;
    public FooBar(Context _context): base(_context)
    {
        this.context = _context;
    }
}

class Foo
{
    public Baz baz;
    private Context context; 
    public Foo(Context _context)
    {
        baz = new Baz();
        this.context = _context;
    }
}

class Baz
{
    public Baz()
    {
        GetNameOfCaller()
    }

    private void GetNameOfCaller()
    {
       ....
       ....
       _className = ....;
    }
    private string _className;
}

Upvotes: 4

Views: 204

Answers (3)

Tim Schmelter
Tim Schmelter

Reputation: 460208

You could use System.Diagnostics.StackTrace:

public class Foo 
{
    public void MethodBah()
    {
        System.Diagnostics.StackTrace t = new System.Diagnostics.StackTrace();
        MethodBase callingMethod = t.GetFrame(1).GetMethod();
        Type callingMethodType = callingMethod.DeclaringType;
        string className = callingMethodType.Name;
    }
}

Works even in .NET 1.1.


With your (updated) example you have to use t.GetFrame(2).GetMethod() instead of GetFrame(1) to get FooBar instead of Foo because the child- calls the parent constructor.

Upvotes: 4

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64943

I believe that your requirement should be solved using aspect-oriented programming.

OP said in some comment:

[..] Logging purposes for now but may not be limited to it alone [...]

For example, there's an extremely powerful tool called PostSharp which lets you intercept any method call, when it's being called and after it was called:

[Serializable]
public class LogAspect : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
    }

    public override void OnExit(MethodExecutionArgs args)
    {
    }
}

Now you can apply the whole aspect as a regular attribute to a method, class or even to an assembly (thus, all methods within the assembly will be loggable).

You can access called method through MethodExecutionArgs.Method (which is of type MethodBase, and this means that you can access which type declares the whole method through MethodBase.DeclaringType.

With a tool like PostSharp you are adding an extra compilation step, but it has the great advantage that your interceptions are injected during compile-time. That is, it will perform like adding the whole code manually in every method.

You can also implement the same thing creating run-time proxies using Castle DynamicProxy to intercept method calls.

Upvotes: 2

Patrick Hofman
Patrick Hofman

Reputation: 157038

Yes, you can do that for constructors the same way as for regular methods. Just use the CallerMemberName to pass in the name of the calling method. You won't have the class name with it, then you need to walk the StackTrace which is much more complicated.

public class X
{
    public X([CallerMemberName] string caller = null)
    {
        this.Caller = caller;
    }

    public string Caller { get; private set; }
}

Then just call this. The compiler will fill in the caller parameter for you:

static void Main(string[] args)
{
    X x = new X();
    Console.WriteLine($"Caller = {x.Caller}"); // prints Main
}

Upvotes: 7

Related Questions