Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 除了无法通过Span外,还有什么可行的替代方案<;T>;变成lambda的表情?_C# - Fatal编程技术网

C# 除了无法通过Span外,还有什么可行的替代方案<;T>;变成lambda的表情?

C# 除了无法通过Span外,还有什么可行的替代方案<;T>;变成lambda的表情?,c#,C#,我有一个这种形状的函数,它可以进行一维寻根: 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 } 这是一个固定的形状,以使算法可重用。考虑这是一个固定的库函数,我不能改变它(或者至

我有一个这种形状的函数,它可以进行一维寻根:

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
s以避免分配,但显然不能将
Span
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>;
}
void CallingMethod()
{
跨度k1=stackalloc双[n];
双重回答;
求解((x,o)=>包装器(x,k1,o),输出答案,null);
}
双包装器(双x,只读平移k1,对象o)
{
返回;
}
但这不起作用,因为不能使用lambda表达式在
Span
s上形成闭包。它们也不能在泛型类型中使用,任何装箱和取消装箱都是无效的,不能作为params关键字传递,不能位于实例变量上,等等

有没有办法解决这个问题


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

在捕获的变量中不能使用跨距。然而,指针可以。这可能会消除span的最佳功能,但在一般情况下,您可以修复span并捕获该固定指针,但您需要非常小心,以确保委托调用无法逃脱
固定的
块,也就是说,您不会将委托分发到任何地方。拥有固定指针后,可以在内部重新创建跨距:

Span k1=/。。。
// ...
固定(双*ptr=k1)
{
var evil=ptr;//这是我说服编译器
//我已经考虑过代表是否可以
//超过委托调用的寿命
求解((x,o)=>Wrapper(x,新跨度(邪恶,k1.Length),o),输出答案,null);
}
然而,在您的特定情况下,如果您只是想固定原始跨度(当它已经有效地固定在堆栈上时),那么您最好根本不必担心原始跨度。“不要让委托超过堆栈框架”的要求仍然存在,但编译器对此不太在意,因为您已经违反了所有规则:

double*k1=stackalloc-double[n];
// ...
求解((x,o)=>Wrapper(x,新跨度(k1,n),o),输出答案,null);

显然,这两者都需要
不安全的
修饰符。

记住
Span
表示堆栈上的内存-因此它不是装箱,而是与CLR不能(现在)这一事实有关保证lambda的闭包不会超过调用堆栈帧。您不能使用
内存
?我使用
Span
专门避免堆分配,
内存
在堆上您是否可以使用
内存
+
阵列工具
来避免新的分配?我认为您无法避免内存分配发生在lambda上。如何定义自己的
ValueType
Fun
实现,自己控制生命周期?