Подтвердить что ты не робот

Вызов частного метода, удерживающего стек вызовов

Я пытаюсь найти решение для "перерыва в непубличные методы".

Я просто хочу вызвать RuntimeMethodInfo.InternalGetCurrentMethod(...), передав свой собственный параметр (так что я могу реализовать GetCallingMethod()) или напрямую использовать RuntimeMethodInfo.InternatGetCurrentMethod(ref StackCrawlMark.LookForMyCaller) в моих процедурах ведения журнала. GetCurrentMethod реализуется как:

[MethodImpl(MethodImplOptions.NoInlining)] 
public static MethodBase GetCurrentMethod() 
{     
    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;     
    return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller); 
}

где InternalGetCurrentMethod объявлено: internal: -).

У меня нет проблем с вызовом метода с использованием отражения, но это испортит стек вызовов, и это единственное, что нужно сохранить, иначе оно победит его цель.

Каковы мои шансы на то, что stacktrace будет близка к оригиналу (по крайней мере, на расстоянии разрешенных StackCrawlMark s, которые LookForMe, LookForMyCaller и LookForMyCallersCaller. Есть ли какой-то сложный способ достичь что я хочу?

4b9b3361

Ответ 1

Если мне что-то нравится в С#, это динамические методы.

Они позволяют обойти все цели и намерения создателей .NET.: D

Здесь (потокобезопасное) решение:

(Эрик Липперт, пожалуйста, не читайте это...)

enum MyStackCrawlMark { LookForMe, LookForMyCaller, LookForMyCallersCaller, LookForThread }
delegate MethodBase MyGetCurrentMethodDelegate(ref MyStackCrawlMark mark);
static MyGetCurrentMethodDelegate dynamicMethod = null;

static MethodBase MyGetCurrentMethod(ref MyStackCrawlMark mark)
{
    if (dynamicMethod == null)
    {
        var m = new DynamicMethod("GetCurrentMethod",
            typeof(MethodBase),
            new Type[] { typeof(MyStackCrawlMark).MakeByRefType() },
            true //Ignore all privilege checks :D
        );
        var gen = m.GetILGenerator();
        gen.Emit(OpCodes.Ldarg_0); //NO type checking here!
        gen.Emit(OpCodes.Call,
            Type.GetType("System.Reflection.RuntimeMethodInfo", true)
                .GetMethod("InternalGetCurrentMethod",
                    BindingFlags.Static | BindingFlags.NonPublic));
        gen.Emit(OpCodes.Ret);
        Interlocked.CompareExchange(ref dynamicMethod,
            (MyGetCurrentMethodDelegate)m.CreateDelegate(
                typeof(MyGetCurrentMethodDelegate)), null);
    }
    return dynamicMethod(ref mark);
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Test()
{
    var mark = MyStackCrawlMark.LookForMe; //"Me" is Test _caller_, NOT Test
    var method = MyGetCurrentMethod(ref mark);
    Console.WriteLine(method.Name);
}