gpt4 book ai didi

c# - 除了无法将 Span 传递到 lambda 表达式之外,还有什么可行的替代方法?

转载 作者:行者123 更新时间:2023-12-03 20:58:29 24 4
gpt4 key购买 nike

我有这种形状的功能,它可以进行一维寻根:

public delegate double Fun(double x, object o);

public static void Solve(Fun f, out double y, object o)
{
y = f(1.0, o); // all the irrelevant details of the algorithm omitted
}

这是一个固定的形状,以使算法可重用。考虑这是一个我无法更改的固定库函数(或者至少需要保持通用和可重用,并且不会针对这个问题的细节进行更改)。

我想传入一个需要外部参数的函数 Span<T> s 保留在堆栈上以避免分配,但显然不能推 Span<T> s 到对象中,因为这需要装箱和拆箱。

使用 lambda 表达式,调用代码可能类似于:
void CallingMethod()
{
Span<double> k1 = stackalloc double[n];
double answer;
Solve((x, o) => Wrapper(x, k1, o), out answer, null);
}

double Wrapper(double x, ReadOnlySpan<double> k1, object o)
{
return <some function of x and k1>;
}

但这不起作用,因为您无法在 Span<T> 上形成闭包。带有 lambda 表达式的 s。它们也不能在泛型类型中使用,任何装箱和拆箱都不可用,不能作为 params 关键字传递,不能用于实例变量等。

有没有办法解决这个问题?

只是为了强调这个例子过于简化了。我可能有一个跨度,但我目前正在处理的问题需要通过 4 个跨度。我需要为任意数量的它们进行设计。

最佳答案

跨度不能用于捕获的变量。然而,指针可以。这可能会消除跨度的最佳特性,但在一般情况下,您可以修复跨度并捕获该固定指针,但您需要是 真的很小心确保委托(delegate)调用无法逃脱 fixed阻止,即您没有在任何地方分发代表。获得固定指针后,您可以在内部重新创建跨度:

Span<double> k1 = // ...
// ...
fixed (double* ptr = k1)
{
var evil = ptr; // this is me convincing the compiler that
// I've considered whether the delegate could
// outlive the delegate invocation
Solve((x, o) => Wrapper(x, new Span<double>(evil, k1.Length), o), out answer, null);
}
但是,在您的特定情况下,如果您只是要固定它(当它已经有效地固定在堆栈上时),您可能根本不关心原始跨度。 “不要让委托(delegate)超过堆栈框架”的要求仍然存在,但编译器对此的要求稍低,因为您已经违反了所有规则:
double* k1 = stackalloc double[n];
// ...
Solve((x, o) => Wrapper(x, new Span<double>(k1, n), o), out answer, null);
这两个都需要 unsafe修饰符,很明显。

关于c# - 除了无法将 Span<T> 传递到 lambda 表达式之外,还有什么可行的替代方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59605908/

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