lundi 20 juillet 2015

How to find the method in which an anonymous delegate was declared

I'm trying to do perhaps some dubious caller analysis for logging. Regardless of if I want to actually do it in the end, I'd like to know if what I'm looking for is possible at all. If not, why not? Since it seems it should be possible to me.

Specifically:

    private static Action CreateAnonymousMethod()
    {
        MethodBase declaringMethod = new StackFrame(true).GetMethod();

        return delegate()
        {
            var myFrame = new StackFrame(true);

            // This is *this* anonymous method. I can figure out from the name
            // "<CreateAnonymousMethod>garbage" that when the compiler generated
            // it, it knew the answer, but from the MethodBase itself, I can find
            // no path back to declaringMethod. So this answer is incorrect, but
            // I feel like the data should be around here somewhere.
            MethodBase whatGoesHere = myFrame.GetMethod();

            Assert.AreEqual(declaringMethod, whatGoesHere);
        };
    }

My goal is I want more or less a 'Log' method that can walk up the stack and find the caller. I know the [CallerMemberName] attributes and such, but there is no corresponding attribute for the declaring type of the caller's member, and the caller's member name is a mere string. I'd like to find a proper MemberInfo if possible.

So that led me to finding the caller's method via StackFrame.GetMethod() however for nicer logging I'd like to detect if it's an anonymous delegate, and instead of or in addition to the anonymous delegate's MemberInfo, use the declaring method's MemberInfo.

However, it seems I just can't 'get there from here.' The most frustrating bit is that I know the compiler knew at least while it was compiling, given the name of the anonymous lambda, but I can't seem to find a way back to the MemberInfo at runtime.

It seems like I want some invented property like MemberInfo.DeclaringMember which would for an anonymous method return return the member in which it was declared. Saying that however I realize an anonymous method isn't even a CLR thing, and so by the time you're looking at reflection the information is just flat gone. So I was hoping in the CompilerGeneratedAttribute it would hold onto the original source MemberInfo and I could extract it from the attribute, but the attribute seems to leave no trace of it.

At this point I think my only option is the very brittle attempt to parse the anonymous method name (ha!) and then use that to somehow search for the corresponding MemberInfo.

Anyway, before I give up and go down that route and see how terrible it is, I thought I'd throw a hail mary out to the fine folks here at StackOverflow and see if there's any genius solution I'm missing, or, if my thought process is fundamentally flawed.





Aucun commentaire:

Enregistrer un commentaire