【发布时间】:2019-11-28 00:30:00
【问题描述】:
我目前正在使用此代码尝试动态执行已保存的Func<object>:
public async Task<object> GetFuncResult(string funcName) {
Func<object> func = _savedFuncs[funcName];
bool isAwaitable = func.Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
if (!isAwaitable) return func();
else return await ((Func<Task<object>>)func)();
}
如果有人存储Func<Task<object>> 或Func<[anything]>,则此代码可以正常工作。但如果有人存储 Func<Task<string>>(或任务中的任何其他通用参数),它就会中断。
Unable to cast object of type Func<Task<System.String>> to type Func<Task<System.Object>>
我的问题是:此时我如何等待Func<Task<Something>> 的结果并将该值作为object 返回?
完整的测试代码:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
static Dictionary<string, Func<object>> _savedFuncs;
static async Task Main(string[] args)
{
_savedFuncs = new Dictionary<string, Func<object>>();
Func<Task<string>> myTask = async () => { return "Test Success"; };
_savedFuncs.Add("myFunc", myTask);
Console.WriteLine((await GetFuncResult("myFunc")) ?? "No Value Returned");
Console.ReadKey();
}
public static async Task<object> GetFuncResult(string funcName)
{
Func<object> func = _savedFuncs[funcName];
bool isAwaitable = func.Method.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
if (!isAwaitable) return func();
return await ((Func<Task<object>>)func)();
}
}
}
【问题讨论】:
-
你为什么把 Object 作为泛型的类型? 不使用对象作为类型实际上是发明/实现泛型的目的。在不知道这些任务可能具有的具体返回值的情况下,我们无能为力。
-
@Christopher 我很欣赏这个问题。这些函数实际上可以返回任何对象。这本质上是一个组合根,它允许用户注册一个表示对象的函数,该对象实际上可以是任何东西。稍后他们可以根据需要取出该对象。
-
然后按字面意思执行
Task<T> GetFuncResult<T>(string funcName) -
@Selvin 这个例子你没有错。 (只是稍微)更复杂的实际代码需要用户的一些灵活性签名。他们中的大多数都是通用的,如
GetFuncResult<T>(...),你的建议会奏效。但是其中有几个就像GetFuncResult(Type type, ...),这是行不通的。就像我希望的那样简单。我需要演示的非泛型方法签名才能工作。 -
在很多情况下,反射并没有错,这可能就是其中之一。另外值得注意的是,反射是在内部缓存的,因此您的性能可能仍然很不错。
标签: c# delegates generic-programming