Suppose there is a class that calls a constructor in a method and creates a type.

Is it possible implicitly in the class constructor to get a reference to the class without explicitly passing this to the constructor?

Example:

  public class A { public void MethodA() { var b = new B(); } } public class B { public B() { // каким-то образом неявно получаем ссылку на класс, который вызвал конструктор. // Т.е в данном случае ссылка на экземпляр A } } 

If I am not mistaken, then in IL , a reference to the calling code is always implicitly passed as the first argument.

PS There are no problems. For the sake of interest.

  • nothing is unclear :) try the code example to add - Grundy
  • @Grundy added. - iluxa1810

1 answer 1

No, you cannot get an instance of the calling class. This information is not even at the level of IL. Constructor B , decompiled into ILDasm, looks like this:

 .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Размер кода: 9 (0x9) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: nop IL_0007: nop IL_0008: ret } // end of method B::.ctor 

It has no parameter declarations, so there are no hidden parameters.


What you can find out is which particular method is calling you without specifying an instance of the class. This is done like this:

 [MethodImpl(MethodImplOptions.NoInlining)] public B() { MethodBase callingMethod = new StackFrame(1).GetMethod(); Console.WriteLine($"Called from type: {callingMethod.DeclaringType.FullName}, " + $"calling method name: {callingMethod.Name}"); } 

My output is:

 Called from type: Test.A, calling method name: MethodA 

You create a stack frame starting at 1 above your current frame, and request a method. Having a reflection-method handle, you can get information from it.

Notice that I applied the MethodImplOptions.NoInlining attribute to disable embedding this method at the call point, otherwise the wrong trace information could get into the stack trace.

Another important point: the StackFrame request is a costly, expensive operation, so you should not apply this solution in the production code. If you want information about that. who called you, in the production code, you should trust this to the compiler and use the [CallerMemberName] attribute, available from .NET 4.5:

 public B([CallerMemberName] string callerName = null, [CallerFilePath] string callerFile = null, [CallerLineNumber] int callerLineNumber = -1) { Console.WriteLine($"Called from method: {callerName}, " + $"located {callerFile}@{callerLineNumber}"); } 

Displays:

 Called from method: MethodA, located D:\full path here\Test\Program.cs@42 
  • And in the stack it is impossible to rummage to find? - Qwertiy
  • @Qwertiy: The Internet does not know the way. That is, you can probably get into the native code and find the desired parameter in the stack, but I doubt that this is a supported script. - VladD
  • @VladD, I think it was already almost identical question - Grundy