gpt4 book ai didi

c# - 如何在 C# 中将带参数的函数绑定(bind)到包中

转载 作者:太空狗 更新时间:2023-10-29 21:33:14 26 4
gpt4 key购买 nike

我正在使用 C# 编写线程池。

这个线程池需要支持执行不同类型的函数。

下面是我需要的:

  1. 将函数及其参数绑定(bind)到仿函数(或称可调用对象)中,其签名应为 void(void)
  2. 得到一个System.Threading.Tasks< TResult >代表我们可调用包的返回值

在 CPP 中,我可以使用一些模板魔术来做到这一点:

template <typename funtype, typename ...argstype>
std::future<typename std::result_of<funtype(argstype...)>::type> async(funtype&& func, argstype&&... args) {
//start function body↓

typedef std::packaged_task<std::result_of<funtype(argstype...)>::type(argstype...)> task_type;
auto task = std::make_shared<task_type>(std::forward<funtype>(func));

// bind to a callable object(functor) with signature void(void)
auto whatINeed= std::bind([task](argstype... args) mutable {
(*task)(std::forward<argstype>(args)...);
}, std::forward<argstype>(args)...);

//and we return the std::future which represents the return value of our package
//in C#, i need to return an Task<TResult>
return task->get_future();
}

在 C# 中,现在我写了:

public Task<TResult> async<TResult>(Delegate func, params object[] args)
{
var stdPromiseXD = new TaskCompletionSource<TResult>();
// the lambda is a callable object with signature void(void)
works.Enqueue(() =>
{
try
{
stdPromiseXD.SetResult((TResult)func.DynamicInvoke(args));
}
catch (Exception ex)
{
stdPromiseXD.SetException(ex);
}
});
// return the Task which equals std::future in CPP
return stdPromiseXD.Task;
}

但是这个C#版本不如CPP版本。首先它不支持非返回函数,其次 DynamicInvoke 方法在某些情况下可能会非常慢。

那么谁能告诉我如何在 C# 中更优雅地将函数和参数绑定(bind)到包中?

最佳答案

我推荐使用 Func<TResult>Action而不是委托(delegate),然后在调用代码中使用闭包来简化使用。 Func 是一个返回结果的通用强类型委托(delegate),而 Action 是一个不返回结果的通用强类型委托(delegate)。

public Task<TResult> Enqueue<TResult>(Func<TResult> func)
{
var stdPromiseXD = new TaskCompletionSource<TResult>();
// the lambda is a callable object with signature void(void)
works.Enqueue(() =>
{
try
{
stdPromiseXD.SetResult((TResult)func());
}
catch (Exception ex)
{
stdPromiseXD.SetException(ex);
}
});
// return the Task which equals std::future in CPP
return stdPromiseXD.Task;
}

public Task Enqueue(Action action)
{
return Enqueue<object>(() =>
{
action();
return null;
});
}

我这样调用它:

var arg1 = "x1";
var arg2 = "2nd";
var arg3 = "third";

var resultTask1 = tp.Enqueue(() => DoConsoleWrite(arg1, arg2, arg3));
var resultTask2 = tp.Enqueue(() => SumAllNumbers(1, 2, 3, 4, 5));
var resultTask3 = tp.Enqueue(() => ThrowException());

while (tp.Pop()) { }

resultTask1.GetAwaiter().GetResult();
var result2 = resultTask2.GetAwaiter().GetResult();
var result3Exception = resultTask3.Exception;

使用闭包的替代方法是为 func 的每个参数计数创建重载(Func<TResult>, Func<T1,TResult>, Func<T1,T2,Result>, etcAction, Action<T1>, Action<T1,T2>, etc)

关于c# - 如何在 C# 中将带参数的函数绑定(bind)到包中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52058316/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com