猿问

如何在 C# 中制作一个通用的可超时函数包装器?

我有一堆阻塞呼叫的功能,在网络连接丢失或其他问题的情况下可能会挂起。我想制作一个通用包装器,允许使用指定的 timout 和参数运行传递的函数。


一个函数原型:


public static double Func1(string ip, string username, string password);

public static int Func2(string ip, string username, string password, string dir);

我的包装:


    public static T? ExecuteAsync<T>(Func<object[], T> func, int timeout /* sec */, params object[] args) where T : struct

    {

        var task = Task.Factory.StartNew(() => func(args));

        if (task.Wait(timeout * 1000))

            return task.Result;

        return null;

    }

预期用途:


var res1 = ExecuteAsync<double>(Func1, 30, "1.1.1.1", "user", "looser");

var res2 = ExecuteAsync<int>(Func2, 20, "1.1.1.1", "user", "looser", "home");

这里的编译器错误(与调用一致ExecuteAsync):


错误 CS1503 参数 1:无法从“方法组”转换为“功能”


我找到了一个可编译的代码


var res = ExecuteAsync((args) => Func1(args[0].ToString(), args[1].ToString(), args[2].ToString()), 50, "ip", "user", "pass");

它太重且难以阅读。可以简化吗?如何修复原始错误?也许还有另一种方法可以达到目标?

我看到了带有 的示例Action,但是我的函数正在返回一个值,并且它们具有不同的参数列表。


杨__羊羊
浏览 125回答 1
1回答

狐的传说

Func1您遇到的问题是具有三个字符串参数的签名,而您的ExecuteAsync方法的第一个参数需要一个以对象数组作为参数的“方法”,即object[]!=string, string, stringpublic static double Func1(string ip, string username, string password);Func<object[], T>您可以拥有的最简单的解决方案是标准化所有“阻塞函数”的签名。在这种情况下,您的情况将如下面的代码所示。你失去了类型安全。Thread班级使用这种方法static void Main(string[] args) {&nbsp; &nbsp; var res1 = ExecuteAsync<double>(Func1, 30, "1.1.1.1", "user", "looser");}public static double Func1(object[] args) {&nbsp; &nbsp; string ip = (string)args[0], username = (string)args[1], password = (string)args[2];&nbsp; &nbsp; // do some work&nbsp;&nbsp; &nbsp; return 0.0;}public static T? ExecuteAsync<T>(Func<object[], T> func, int timeout /* sec */, params object[] args) where T : struct {&nbsp; &nbsp; var task = Task.Factory.StartNew(() => func(args));&nbsp; &nbsp; if (task.Wait(timeout * 1000))&nbsp; &nbsp; &nbsp; &nbsp; return task.Result;&nbsp; &nbsp; return null;}如果您不想失去类型安全性,您可以创建ExecuteAsync方法的多个重载 - 类似于 .NET 框架为 .NET 创建多个重载的方式Func。在这种情况下,您的ExecuteAsync方法将如下所示。您可以为 1、2、4、5 arg 方法创建其他重载,就像Func实现方式一样public static TRes? ExecuteAsync<T1, T2, T3, TRes>(Func<T1, T2, T3, TRes> func, int timeout /* sec */, T1 arg1, T2 arg2, T3 arg3) where TRes : struct {&nbsp; &nbsp; var task = Task.Factory.StartNew(() => func(arg1, arg2, arg3));&nbsp; &nbsp; if (task.Wait(timeout * 1000))&nbsp; &nbsp; &nbsp; &nbsp; return task.Result;&nbsp; &nbsp; return null;}
随时随地看视频慕课网APP
我要回答