Reputation: 817
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
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
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
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