我有一个类负责存储一堆异步函数以便稍后执行它们。每个函数的签名仅在Task类型上有所不同。下面是类:
public class FuncStore<TParameters> {
private readonly Dictionary<string, object> _funcCache = new();
public void AddFunc<T>(string key, Func<TParameters, Task<T>> value) {
_funcCache.Add(key, value);
}
public async Task ExecuteAllAsync(TParameters parameters) {
foreach(var (_, func) in _funcCache) {
// Problem here. How do I invoke each lambda?
}
}
}
下面是context的parameters类:
public class DefaultParameters {
public string SomeProperty { get; set; }
}
下面是一个使用的例子:
var store = new FuncStore<DefaultParameters>();
var lambda01 = (DefaultParameters parameters) => {
var str = parameters.SomeProperty + "01"; // Whatever
return Task<string>.FromResult(str); // Simulate async op
};
var lambda02 = (DefaultParameters parameters) => {
var number = Convert.ToInt32(parameters.SomeProperty) + 2; // Whatever
return Task<int>.FromResult(number); // Simulate async op
};
// These both lambdas differ on their return type
// one is Task<string> and the other is Task<int>
store.AddFunc("01", lambda01);
store.AddFunc("02", lambda02);
// Many other lambdas and additions later...
var parameters = new DefaultParameters();
await store.ExecuteAllAsync(parameters);
问题是我不知道如何调用这些lambda。以下是我到目前为止的尝试:
public async Task ExecuteAllAsync(TParameters parameters) {
foreach(var (_, func) in _funcCache) {
// Problem here. How do I invoke each lambda?
// Attempt 1:
var typedFunc = func as Func<TParameters, Task<object>>; // NullReferenceExeption, the cast fails
await typedFunc(parameters);
// Attempt 2 (almost):
var asDelegate = func as Delegate;
// I manage to get the task...
var task = (Task)asDelegate.DynamicInvoke(new object[]{ parameters });
// ... but if I await it, I get a compile error: "Argument 1: cannot convert from 'void' to 'bool'"
Console.WriteLine(await task);
}
await Task<int>.FromResult(0); // Just to make the compiler happy while I debug
}
这是。net提琴
任何想法?提前谢谢。
一种方法是在函数缓存和委托中都使用dynamic
:
var lambda01 = (DefaultParameters parameters) => {
var str = parameters.SomeProperty + "01"; // Whatever
return Task.FromResult<dynamic>(str); // Simulate async op
};
:
private readonly Dictionary<string, dynamic> _funcCache = new();
public void AddFunc(string key, Func<TParameters, Task<dynamic>> value) {
_funcCache.Add(key, value);
}
工作示例:https://dotnetfiddle.net/rTm8ZM
这里是另一个不使用dynamic
的实现。
public class FuncStore<TParameters>
{
private readonly Dictionary<string, Func<TParameters, object>> _funcCache = new();
public void AddFunc<T>(string key, Func<TParameters, Task<T>> value)
{
_funcCache.Add(key, value);
}
// Scenario 1: if you don't care about the results of tasks
public async Task ExecuteAllAsync(TParameters parameters)
{
foreach (var (_, func) in _funcCache)
{
var function = (Task)func(parameters);
await function;
}
}
// Scenario 2: if you care about the results of Task<T>
public async Task<string> ExecuteAllAsync2(TParameters parameters)
{
// string accumulator to store the results, but it can be a List<object> or whatever you need
string accumulatedResult = string.Empty;
foreach (var (_, func) in _funcCache)
{
var function = func(parameters);
// individual checks for casting
if (function is Task<object> stringTask)
{
accumulatedResult += await stringTask;
}
else if (function is Task<int> intTask)
{
accumulatedResult += (await intTask).ToString();
}
//(...)
}
return accumulatedResult;
}
}