繁体   English   中英

一个聪明的技巧,以防止任务 <IDisposable> 从没有等待的C#using子句中使用

[英]A clever trick to prevent Task<IDisposable> from being used in C# using clause without await

我有许多方法,目前返回一个等待的Task<IDisposable>

有没有办法更改返回类型,以便以下将成为编译时错误?

using (GetExclusiveLockAsync())
{
    ...
}

我的想法是让编译器提醒我,我应该像这样编写它:

using (await GetExclusiveLockAsync())
{
    ...
}

实际上,GetExclusiveLockAsync返回Task<IDisposable> ,它还实现了IDisposable(通过基本Task类)。 两个片段都编译,但其中一个是错误的。 我不想处理任务,只有它的结果!

是否有一个聪明的技巧使第一个编译时错误?

更新 :根据目前的评论,似乎所展示的模式令人困惑。 我现在已将方法的名称从原始GetAsyncGetExclusiveLockAsync以更好地说明实际的预期用途。 它基本上是一个异步同步锁,这是我不需要在using行中声明变量也不需要在以下块中使用它的主要原因。 它仅用于保护它所包围的代码块免受并行影响。

是否有一个聪明的技巧使第一个编译时错误?

是的,您可以将返回类型更改为其他类型。

我在AsyncEx库中使用此方法,使用AwaitableDisposable<T>类型 简而言之:

public struct AwaitableDisposable<T> where T : IDisposable
{
    private readonly Task<T> _task;
    public AwaitableDisposable(Task<T> task) { _task = task; }

    public TaskAwaiter<T> GetAwaiter() => _task.GetAwaiter();
    public ConfiguredTaskAwaitable<T> ConfigureAwait(bool continueOnCapturedContext) =>
        _task.ConfigureAwait(continueOnCapturedContext);

    public Task<T> AsTask() => _task;
    public static implicit operator Task<T>(AwaitableDisposable<T> source) =>
        source.AsTask();
}

您可以从GetExclusiveLockAsync返回AwaitableDisposable<T> ,而不是常规的Task<T> 它是一个最小开销的struct

隐式转换和GetAwaiter / ConfigureAwait方法允许“任务”使用:

// All of these work.
IDisposable key = await GetExclusiveLockAsync();
IDisposable key = await GetExclusiveLockAsync().ConfigureAwait(false);
Task<TDisposable> lockTask = GetExclusiveLockAsync();
using (await GetExclusiveLockAsync()) { }

在某些情况下,隐式转换是不够的,例如,某些Task.WhenAll使用。 对于这些情况,用户可以调用AsTask

// Not pretty, but doable.
await Task.WhenAll(x.GetExclusiveLockAsync().AsTask(),
    y.GetExclusiveLockAsync().AsTask());

当然, AwaitableDisposable<T>的全部目的是它不是一次性的,所以这在编译时失败了:

using (GetExclusiveLockAsync()) { }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM