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
实现,自己控制生命周期?