为什么该程序显示使用seq的错误:
class Program
{
delegate double Sequence(int r);
void F(ref Sequence seq) // Here
{
Sequence seq2 = r =>
{
if (r % 2 == 0)
return seq(r); // Here
else
return seq(2 * r); // Here
};
seq = seq2;
}
static void Main()
{
}
}
错误CS1628无法在内部使用ref,out或in参数'seq' 匿名方法,lambda表达式,查询表达式或局部 函数CsharpRefLambdaTest
问题在于参数seq
是引用类型。但是为什么会这样呢?引用seq
有什么问题?如果未引用seq
,则程序没有错误。
在以seq为参考的同时,有什么方法可以纠正程序?
该程序只是一个测试,它不会做任何事情。
================
我需要使用seq
的值来定义新的序列seq2
,然后分配seq = seq2
。但是seq的值不可用。如果seq
的值不可用,为什么C#允许seq
完全作为引用?
==============================
编辑:
上面的程序只是以下内容的简化版本:
class Program
{
delegate double Sequence(int r);
Sequence G(Sequence seq)
{
Sequence seq2 = r =>
{
if (r % 2 == 0)
return seq(r);
else
return seq(2 * r);
};
return seq2;
}
void F(ref Sequence seq)
{
seq = G(seq);
}
static void Main()
{
}
}
但是我不明白为什么我不能删除G
而添加G inside
F`的定义代码。
答案 0 :(得分:4)
此处的错误消息是:“ CS1628无法在匿名方法,lambda表达式,查询表达式或局部函数内使用ref,out或in参数'seq'”-seq2
是lambda表达式;它与引用类型无关,而是:生存期。毕竟,您可以这样称呼它:
void Foo() {
Sequence bar = SomeMethod; // bar is a LOCAL of Foo
F(ref bar);
// not shown: perhaps do something with bar, perhaps not
}
这时,F
需要以某种方式创建一个lambda,其中包含对堆栈上某个位置的引用(对本地bar
的引用)。现在请注意,作为对象的该lambda可能会超出Foo
的寿命,而bar
将是未定义的(并且可能会被重用的)内存位置。
因此:您不能“捕获”作为ref
,in
和out
传递的参数,此处我在这里宽松地使用“捕获”来表示“在内部使用构成表达式树,委托表达式的lambda或匿名方法的范围;或者在迭代器块或异步延续中。”
只需删除ref
。您不需要它,它也无济于事。如果您打算更改代表,则可以考虑返回组成的代表。
作为替代解决方法:快照值并捕获快照:
void F(ref Sequence seq)
{
var tmp = seq;
seq = r =>
{
if (r % 2 == 0)
return tmp(r);
else
return tmp(2 * r);
};
}
这避免了出现问题的情况,因为快照取消引用 ref
参数,这意味着:现在我们无法捕获堆栈位置。