C# 在只能运行同步时满足异步接口方法

C# 在只能运行同步时满足异步接口方法,c#,interface,com,async-await,C#,Interface,Com,Async Await,我正在使用一个作为COM+对象实现的“API”(我松散地使用这个术语)。据我所知,COM+提供的任何排队功能都不支持,但我对COM+几乎一无所知。把它和盐一起吃。我只有一个方法可用:invoke,它是sync 在某种程度上,我个人才华横溢,围绕这个COM+对象创建了一个WebAPI包装器,它只有一个端点,通过请求的post主体调用COM+对象。这使我能够对Web Api进行异步调用(并从我的应用程序中删除可怕的依赖性) 现在,我正在创建一个库来基本上抽象所有这些混乱,但我决定实现一个提供程序模式

我正在使用一个作为COM+对象实现的“API”(我松散地使用这个术语)。据我所知,COM+提供的任何排队功能都不支持,但我对COM+几乎一无所知。把它和盐一起吃。我只有一个方法可用:
invoke
,它是sync

在某种程度上,我个人才华横溢,围绕这个COM+对象创建了一个WebAPI包装器,它只有一个端点,通过请求的post主体调用COM+对象。这使我能够对Web Api进行异步调用(并从我的应用程序中删除可怕的依赖性)

现在,我正在创建一个库来基本上抽象所有这些混乱,但我决定实现一个提供程序模式,您可以选择直接使用COM+或Web Api包装器。很明显,我有一个接口,同时具有sync和async方法。WebAPI提供程序当然没有问题,因为您可以通过任何一种方式执行HTTP请求,但我的COM+提供程序遇到了麻烦。因为异步不是一个选项

在我看来,我有三个选择:

  • 使用
    NotImplementedException
    “实现”异步接口方法,这违反了接口隔离原则

  • 做一些不明智的事情,比如使用
    Task.Run
    ,我知道在这种情况下,它不是真正的异步的,基本上对任何使用我的库编程的人都是谎言

  • 执行类似于创建接口的同步和异步版本的操作,这从接口隔离的角度来看更好,但从提供程序模式的角度来看更糟。如果我依赖于异步接口,则永远不能使用COM+提供程序;如果我依赖于同步接口,则永远不能使用Web Api提供程序的异步方法

  • 长话短说,我的一般问题是,在需要异步运行某些东西,但需要使用的方法只能同步运行的情况下,您会怎么做?如果没有真正的替代方案,那么满足接口需求的最不具攻击性的方法是什么

    编辑

    我忘了再提一个选项:

  • 在异步实现中调用sync方法,然后简单地返回带有结果的
    Task.FromResult
    。这意味着我没有拉一个新线程(这可能是web应用程序中的一个问题),但我不确定这是否真的比
    任务好。运行
    ,这是在欺骗消费者说这实际上是“异步的”

  • 我找到的解决方案是使用
    Task.FromResult
    返回
    任务
    ,即使没有执行任何异步操作。虽然这实际上不是异步的,但它满足接口的要求。然后我对该方法进行了注释,指出它将运行sync,并应作为委托传递给
    任务。在无法阻止线程的情况下运行
    (例如GUI)。使用
    Task.Run
    并非适用于所有情况(例如web应用程序),而是应由库的使用者决定的实现细节

    也就是说,要真正实现这一点,您需要处理三种
    任务
    场景:完成、故障和取消。下面是执行所有这些操作的实际代码:

    public Task<int> DoSomethingAsync(CancellationToken cancellationToken)  
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled<int>(cancellationToken);
        }
    
        try
        {
            return Task.FromResult<int>(DoSomething());
        }
        catch (Exception e)
        {
            return Task.FromException<int>(e);
        }
    }
    
    public Task DoSomethingAsync(CancellationToken CancellationToken)
    {
    if(cancellationToken.IsCancellationRequested)
    {
    返回任务.fromCancelled(cancellationToken);
    }
    尝试
    {
    返回Task.FromResult(DoSomething());
    }
    捕获(例外e)
    {
    返回任务.FromException(e);
    }
    }
    

    首先,这确保操作没有被取消。如果有,则返回已取消的任务。然后,我们需要做的同步工作被包装在一个try..catch块中。如果抛出异常,我们将需要返回一个出错的任务,其中包括该异常。最后,如果它正确完成,我们将返回一个已完成的任务。

    除了2,我在这里看不到合理的选择。如果你真的不能改变COM的一面,你就不必“撒谎”,这是一个不取决于你的事实,你会尽你最大的努力把行为隐藏起来。如果你能改变它:是的,不,不能改变。不幸的是,它是由我们的POS(这在很大程度上意味着销售点和其他东西)提供商作为“API”提供的第三方DLL。它一直是偏头痛的根源。Task.Run()非常异步。但是COM有一个特性,对象可以告诉操作系统它不是线程安全的。倾向于有用,比它每天以完全不可诊断的方式在你没有源代码的代码中随机崩溃一次要好。当你有确凿的证据证明一个库不是线程安全的,而这样的库从来都不是线程安全的时,你真的必须担心线程安全。给我一个机会。