Home
Options

need separate Hijack methods and scripts for sync and async Main methods?

Just wanted to sanity check that I wasn't missing something. AFAICT I need separate linqpad reference files (that get #load'd from scripts) depending on whether the calling script's Main method is sync or async, and the Hijack method defined in each is either void or async Task.

In the scenario of trying to use an existing logger so any unhandled exceptions are written to the preferred logger (trying to subscribe to UnhandledException didn't work since linqpad is already handling it), I would need to go this route, right? Just trying to understand whether doing it in a single script would be somehow possible and I'm just missing it.

AddOuterCatchSync.linq

#load "lib\ScriptLogging"

void Main()
{

}

void Hijack()
{
    try
    {
        Main();
    }
    catch (Exception ex)
    {
        var logger = GetScriptLogger();
        logger.LogCritical(ex, $"caught sync Main exception from {Util.CurrentQueryPath}");
    }
}

AddOuterCatchAsync.linq

#load "lib\ScriptLogging"

async Task Main()
{
    await Task.Yield();
}

async Task Hijack()
{
    try
    {
        await Main();
    }
    catch (Exception ex)
    {
        var logger = GetScriptLogger();
        logger.LogCritical(ex, $"caught async Main exception from {Util.CurrentQueryPath}");
    }
}

And I have to keep these in separate scripts because trying to define them in the same script (which would be my preference) results in a compile failure CS0111 Type 'UserQuery' already defines a member called 'Hijack' with the same parameter types

Comments

  • Options

    Here's an idea: start by defining the following pair of methods (make them public and put them in My Extensions to make them reusable):

    Task AsAsync (Action a) { a(); return Task.CompletedTask; }
    Task AsAsync (Func<Task> a) => a();
    

    Then you can always make your Hijack method async. To call the main method:

    await AsAsync (Main);
    

    This will work whether the Main method is sync or async.

  • Options

    @JoeAlbahari thank you so much, that works beautifully!

    I put those methods in the #load'd script instead of My Extensions for now since I don't have any other consumers (and I'm trying to avoid putting things in to My Extensions as much as possible, moving to just #load whenever I can) but it worked great!

    The only thing I needed to add as well were overloads for the int-returning cases so now it works for Main whether it's returning void, int, Task, or Task<int> - thank you!!

    including for any others that use this and need to cover those cases as well

    Task AsAsync(Action a) { a(); return Task.CompletedTask; }
    Task AsAsync(Func<int> a) { a(); return Task.CompletedTask; }
    Task AsAsync(Func<Task> a) => a();
    Task AsAsync(Func<Task<int>> a) => a();
    
Sign In or Register to comment.