Call private method retaining call stack
I am trying to find a solution to 'break into non-public methods'.
I just want to call RuntimeMethodInfo.InternalGetCurrentMethod(...)
, passing my own parameter (so I can implement GetCallingMethod()
), or directly use RuntimeMethodInfo.InternatGetCurrentMethod(ref StackCrawlMark.LookForMyCaller)
in my logging routines. GetCurrentMethod
is implemented as:
[MethodImpl(MethodImplOptions.NoInlining)]
public static MethodBase GetCurrentMethod()开发者_如何转开发
{
StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;
return RuntimeMethodInfo.InternalGetCurrentMethod(ref lookForMyCaller);
}
where InternalGetCurrentMethod
is declared: internal :-).
I have no problem calling the method using reflection, but this messes up the call stack and that is just the one thing that has to be preserved, otherwise it defeats its purpose.
What are my odds of keeping the stacktrace close to the original (at least within the distance of the allowed StackCrawlMark
s, which are LookForMe
, LookForMyCaller
and LookForMyCallersCaller
. Is there some complex way to achieve what I want?
If there's one thing I love about C#, it's dynamic methods.
They let you bypass every goal and intention of the .NET creators. :D
Here's a (thread-safe) solution:
(Eric Lippert, please don't read this...)
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's _caller_, NOT Test
var method = MyGetCurrentMethod(ref mark);
Console.WriteLine(method.Name);
}
精彩评论