Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 StackCrawlMarks, which are LookForMe, LookForMyCaller and LookForMyCallersCaller. Is there some complex way to achieve what I want?

like image 310
Edwin Avatar asked Feb 28 '11 14:02

Edwin


People also ask

Can we call private method from public method?

An object user can use the public methods, but can't directly access private instance variables. You can make methods private too. Object users can't use private methods directly. The main reason to do this is to have internal methods that make a job easier.

Whats the point of private methods?

Private methods are useful for breaking tasks up into smaller parts, or for preventing duplication of code which is needed often by other methods in a class, but should not be called outside of that class.

How do you call a private method inside a public function in C++?

class ClassOne { private: void methodOne(); public: void methodTwo(); }; So I should be able to access methodOne through methodTwo but without writing { methodTwo();} beside methodOne. Help me please? If you want one method to call the other, just do so.

When should methods be private?

Private methods are typically used when several methods need to do the exact same work as part of their responsibility (like notifying external observers that the object has changed), or when a method is split in smaller steps for readability.


1 Answers

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);
}
like image 114
user541686 Avatar answered Oct 31 '22 06:10

user541686