mercredi 16 novembre 2016

How to accurately determine whether a method was called by an async method

I am trying to determine whether a particular method was called by an async method.

This answer (which was, granted, describing a somewhat different set of circumstances) suggested using CallerMemberName attribute to find the name of the calling method. Indeed, the signature of my method looks like this:

public void LogCallAsync([CallerMemberName] string caller = "", params object[] parameters)

which works great if you're doing something like

logger.LogCallAsync();

It would also work great if you have a fixed number of parameters. However, given that the next parameter is of type params object[], obviously that isn't the case, so if you try to do something like

logger.LogCallAsync(someObject, someOtherObject)

I'll get a compile exception because someObject isn't a string. I tried the following as a workaround:

logger.LogCallAsync(nameof(CurrentMethod), someObject, someOtherObject);

which is pretty ugly. Actually, I'd prefer it if I didn't have to do that, so if anyone has any suggestions in that regard that would be great, but on to my main question: is there some way of preventing people from calling this improperly? In particular, I'd like to know if "CurrentMethod" is, in fact, an actual async method.

If I look at an instance of StackTrace, for example, is there a reliable way of telling based on that? This article (if I'm reading it correctly) seems to imply that my current solution (see my code sample below) is correct, but it's not really an "authoritative" source and it's about 5 years old at this point.

Let me show a code sample to illustrate how I'm trying to solve this right now:

private static void GetCaller()
    {
        StackTrace stack = new StackTrace();
        MethodBase method = stack.GetFrame(1).GetMethod();

        Trace.TraceInformation("Method name: " + method.Name);
    }

    // Some arbitrary async method
    private static async Task UseReflection()
    {
        // Do some kind of work
        await Task.Delay(100);

        // Figure out who called this method in the first place
        GetCaller();
    }

    static void Main(string[] args)
    {
        // AsyncPump is basically to make Async work more like it does on a UI application
        // See this link: http://ift.tt/2dC2wf9
        AsyncPump.Run(async () =>
        {
            // In this case, it identifies the calling method as "MoveNext"
            await UseReflection();
        });

        // In this case, it identifies the calling method as "Main"
        GetCaller();
    }

I'm using Visual Studio 2015 and .NET 4.6 for what it's worth. My question, then, is: can I guarantee that code will always work in a way that's similar to what I have above? For example, if GetCaller was called by an async method, will I always get MoveNext off the stack trace? Also, does anyone know if Microsoft documents that somewhere (in case I'm asked to prove that my solution will work)?





Aucun commentaire:

Enregistrer un commentaire