【发布时间】:2021-10-31 14:48:44
【问题描述】:
我有一些属性类:
public class Test<TInput, TResult>
{
public Func<Func<TInput, TResult>, Func<TInput, TResult>> MyProperty { get; set; }
}
TResult 类型可以是任何类型:int、decimal、Task、Task<>。
假设TResult 是Task 或Task<>(仅用于此示例)。请不要建议转换为Func<TInput, Task<TResult>> - 这对我来说是不可能的。
现在我有一些方法(不编译,见下文):
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(我知道TResult是Task或者我可以检查,但编译器不知道)。
我也尝试过继续:
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<TResult>。
我想应该有办法做到这一点(我正在玩强制转换和委托转换,但我无法让它工作)。
还请记住,它不允许在异步上阻塞,因此不能仅在任务上使用 .Result 或 .Wait()。
之前假设TResult 是Task-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<TInput, TResult>对象,仅当TResult为Task或Task<T>时? -
await ifTrue.Invoke(input)不会编译,因为TResult不是Func<TInput, TResult> ifTrue中的类任务类型。编译时没有任何东西可以告诉编译器TResult是等待类型。 -
@HimBromBeere,你是对的,但我不能 - 对整个应用程序进行许多更改。所以我尝试寻找其他方式(不是最好的,我知道)
-
@JeremyLakeman 不,它应该返回一个
TResult。这是一个嵌套的 lambda。它以inputDelegate => async input => ...开头
标签: c# .net .net-core delegates task