【问题标题】:Async delegates casting/conversion异步委托转换/转换
【发布时间】:2021-10-31 14:48:44
【问题描述】:

我有一些属性类:

public class Test<TInput, TResult>
{
    public Func<Func<TInput, TResult>, Func<TInput, TResult>> MyProperty { get; set; }
}

TResult 类型可以是任何类型:intdecimalTaskTask&lt;&gt;

假设TResultTaskTask&lt;&gt;(仅用于此示例)。请不要建议转换为Func&lt;TInput, Task&lt;TResult&gt;&gt; - 这对我来说是不可能的。

现在我有一些方法(不编译,见下文):

public void MyMethod(Func<TInput, Task<bool>> predicate, Func<TInput, TResult> ifTrue)
{
    this.MyProperty = inputDelegate => async input =>
    {
        var predicateResult = await predicate.Invoke(input);

        return predicateResult ? await ifTrue.Invoke(input) : await inputDelegate.Invoke(input);
    };
}

显然有编译时错误说async不能在这里使用,因为这个委托的返回类型应该是Task-like或void(我知道TResultTask或者我可以检查,但编译器不知道)。

我也尝试过继续:

public void MyMethod2(Func<TInput, Task<bool>> predicate, Func<TInput, TResult> ifTrue)
{
    this.MyProperty = inputDelegate => input =>
    {
        return predicate.Invoke(input)
            .ContinueWith(t => t.Result ? ifTrue.Invoke(input) : inputDelegate.Invoke(input));
    };
}

此方法也不会编译,因为延续结果不是TResult,而是Task&lt;TResult&gt;

我想应该有办法做到这一点(我正在玩强制转换和委托转换,但我无法让它工作)。

还请记住,它不允许在异步上阻塞,因此不能仅在任务上使用 .Result.Wait()

之前假设TResultTask-like 类型,是否有可能以某种方式处理这种情况?

谢谢

更新

我试图等待predicate 的内部延续:

public void MyMethod3(Func<TInput, Task<bool>> predicate, Func<TInput, TResult> ifTrue)
{
    this.MyProperty = inputDelegate => input =>
    {
        var continuationTask = predicate.Invoke(input)
            .ContinueWith
            (
                async t =>
                {
                    var task = (Task)(object)(t.Result ? ifTrue.Invoke(input) : inputDelegate.Invoke(input));

                    await task;

                    object result = null;

                    var taskType = task.GetType();

                    if (taskType.IsGenericType) // Task<>
                    {
                        // task is already completed because of await above
                        result = taskType.GetProperty(nameof(Task<object>.Result)).GetValue(task);
                    }

                    return result;
                }
            ).Unwrap(); // make return type Task<object> from Task<Task<object>>

        // InvalidCastException -> if TResult is something different form Task<object>
        // if TResult is Task<int> then cast fails (because Task<int> and Task<object> are different types and task is not co/contra -variant)
        return (TResult)(object)continuationTask;
    };
}

但我无法将最终结果转换为所需的类型。

【问题讨论】:

  • 只是不要将异步类型与同步类型混合。 bool、int 和 Task 绝对没有任何共同点,因此拥有涵盖两者的通用方法几乎没有用处,是吗?
  • 如果我理解正确,您希望MyMethod 可用于Test&lt;TInput, TResult&gt; 对象,仅当TResultTaskTask&lt;T&gt; 时?
  • await ifTrue.Invoke(input) 不会编译,因为TResult 不是Func&lt;TInput, TResult&gt; ifTrue 中的类任务类型。编译时没有任何东西可以告诉编译器 TResult 是等待类型。
  • @HimBromBeere,你是对的,但我不能 - 对整个应用程序进行许多更改。所以我尝试寻找其他方式(不是最好的,我知道)
  • @JeremyLakeman 不,它应该返回一个TResult。这是一个嵌套的 lambda。它以inputDelegate =&gt; async input =&gt; ... 开头

标签: c# .net .net-core delegates task


【解决方案1】:

您的问题似乎是让编译器相信您确定TResultTask/Task&lt;T&gt;

如果你使用扩展方法,你可以写一个MyMethod,这样它只适用于Test对象,其中TResultTask,另一个重载只适用于Test对象,其中TResultTask&lt;T&gt;:

public static class TestExtensions {
    public static void MyMethod<TInput>(this Test<TInput, Task> test, Func<TInput, Task<bool>> predicate, Func<TInput, Task> ifTrue)
    {
        test.MyProperty = inputDelegate => async input =>
        {
            var predicateResult = await predicate.Invoke(input);

            if (predicateResult) {
                await ifTrue(input);
            } else {
                await inputDelegate(input);
            }
        };
    }
    public static void MyMethod<TInput, TResult>(this Test<TInput, Task<TResult>> test, Func<TInput, Task<bool>> predicate, Func<TInput, Task<TResult>> ifTrue)
    {
        test.MyProperty = inputDelegate => async input =>
        {
            var predicateResult = await predicate.Invoke(input);
            return predicateResult ? await ifTrue(input) : await inputDelegate(input);
        };
    }
}

【讨论】:

  • 不错的一个。实际上,当TResult 不是Task 时,它甚至会隐藏带有异步谓词的方法。谢谢。
猜你喜欢
  • 2016-05-29
  • 1970-01-01
  • 2023-03-13
  • 2013-06-18
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多