#c_sharp #net
Допустим, есть класс, который вызывает в методе конструктор и создает тип. Можно ли неявно в конструкторе класса получить ссылку на класс без явной передачи this в конструктор? Пример: public class A { public void MethodA() { var b = new B(); } } public class B { public B() { // каким-то образом неявно получаем ссылку на класс, который вызвал конструктор. // Т.е в данном случае ссылка на экземпляр A } } Если не ошибаюсь, то в IL в качестве первого аргумента всегда неявно передается ссылка на вызывающий код. P.S Задач никаких нету. Интереса ради.
Ответы
Ответ 1
Нет, вы не можете получить экземпляр вызывающего класса. Этой информации нету даже на уровне IL. Конструктор B, декомпилированный в ILDasm, выглядит так: .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 У него нету объявления параметров, так что скрытых параметров нету. То, что вы можете выяснить — это какой конкретно метод вас вызывает, без указания на экземпляр класса. Это делается так: [MethodImpl(MethodImplOptions.NoInlining)] public B() { MethodBase callingMethod = new StackFrame(1).GetMethod(); Console.WriteLine($"Called from type: {callingMethod.DeclaringType.FullName}, " + $"calling method name: {callingMethod.Name}"); } У меня выводит: Called from type: Test.A, calling method name: MethodA Вы создаёте stack frame, начинающийся на 1 выше вашего текущего фрейма, и запрашиваете метод. Имея reflection-дескриптор метода, вы можете получить информацию из него. Заметьте, что я применил атрибут MethodImplOptions.NoInlining, чтобы запретить встраивать этот метод в точку вызова, в противном случае в stack trace могла бы попасть не та информация. Ещё один немаловажный момент: запрос StackFrame — затратная, дорогостоящая операция, поэтому не стоит применять это решение в production-коде. Если вы хотите информацию о том. кто вас вызвал, в production-коде, стоит доверить это компилятору и воспользоваться атрибутом [CallerMemberName], доступным начиная с .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}"); } Выводит: Called from method: MethodA, located D:\full path here\Test\Program.cs@42
Комментариев нет:
Отправить комментарий