异步委托 casting/conversion
Async delegates casting/conversion
我有一些 class 和 属性:
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
不能在这里使用,因为 return 这个委托的类型应该是 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
类型是否有可能以某种方式处理这种情况?
谢谢
更新
我试图等待 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;
};
}
但我无法将最终结果转换为所需的类型。
您的问题似乎是让编译器相信您确定 TResult
是Task
/Task<T>
.
如果您使用扩展方法,您可以编写一个 MyMethod
,使其仅适用于 Test
个对象,其中 TResult
是 Task
,另一个重载仅适用于 Test
个对象,其中 TResult
是 Task<T>
:
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);
};
}
}
我有一些 class 和 属性:
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
不能在这里使用,因为 return 这个委托的类型应该是 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
类型是否有可能以某种方式处理这种情况?
谢谢
更新
我试图等待 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;
};
}
但我无法将最终结果转换为所需的类型。
您的问题似乎是让编译器相信您确定 TResult
是Task
/Task<T>
.
如果您使用扩展方法,您可以编写一个 MyMethod
,使其仅适用于 Test
个对象,其中 TResult
是 Task
,另一个重载仅适用于 Test
个对象,其中 TResult
是 Task<T>
:
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);
};
}
}