将任务转换为任务<t>(返回类型为T的包装任务)

时间:2017-08-27 15:58:55

标签: c# generics task continuewith

我已阅读this question但在我看来更简单,因为我不必使用Result财产。所以我想知道我是否可以采用比Stephen Cleary的回答更简单的方法。

假设我有这个简单的界面。

internal interface IBinaryDataReadable
{
    Task Load(AsyncDataReader reader);
}

该接口提供了异步加载对象的方法。它没有返回任何东西,因为加载结果是对象本身。

(接口是内部的,因此明确实现,以避免暴露实现。)

以下是我加载二进制数据的方法。

data = new BinaryData();
await ((IBinaryDataReadable)data).Load(reader);

我想让这个更流畅,更详细,所以我写这个扩展方法

internal static Task<TData> Load<TData>(this TData data, AsyncDataReader reader)
    where TData : IBinaryDataReadable 
        => data.Load(reader).ContinueWith(t => data, TaskContinuationOptions.ExecuteSynchronously);

现在加载就像这样。

data = await new BinaryData().Load(reader);

这里有什么我应该担心使用这种方法吗?,例如异常处理等?

1 个答案:

答案 0 :(得分:4)

使用ContinueWith

可以使用async / await和foregoes完成同样的操作
internal static async Task<TData> Load<TData>(this TData data, AsyncDataReader reader) 
    where TData : IBinaryDataReadable {
    await data.Load(reader);
    return data;
}

这样,如果需要,您甚至可以在方法中包含异常处理。 然而,扩展方法在流畅的接口方面没有太大作用,因为该方法返回需要等待的任务。

并且您必须显式调用泛型扩展,否则您只是在等待导致编译错误时解析为void的类型上调用本地成员。

data = await new BinaryData().Load<BinaryData>(reader); 

我建议将扩展方法重命名为不会与接口上的现有成员冲突的扩展方法。

data = await new BinaryData().LoadAsync(reader);
  

我想知道使用ContinueWith是否会引入问题

我不认为它引入任何问题,除了不能保护异常。但是可以通过检查这种情况并将其冒泡来管理。

internal static Task<TData> LoadAsync<TData>(this TData data, AsyncDataReader reader)
    where TData : IBinaryDataReadable {
    return data.Load(reader)
        .ContinueWith(t => {
            var error = t.Exception;
            if (error != null && t.IsFaulted)
                throw error;
            return data;
        }, TaskContinuationOptions.ExecuteSynchronously);
}

虽然,在我看来,使用async / await更清晰,更易于阅读和实现。

相关问题