为什么不能在lambda表达式中使用ref或out参数?
我今天遇到了错误并找到了解决方法,但我仍然很好奇为什么这是编译时错误。
CS1628:无法在匿名方法,lambda表达式或查询表达式中的ref或out参数'parameter'中使用
这是一个简单的例子:
private void Foo()
{
int value;
Bar(out value);
}
private void Bar(out int value)
{
value = 3;
int[] array = { 1, 2, 3, 4, 5 };
int newValue = array.Where(a => a == value).First();
}
答案 0 :(得分:111)
Lambdas看起来更改了他们捕获的变量的生命周期。例如,以下lambda表达式导致参数p1 live 比当前方法帧更长,因为在方法帧不再位于堆栈之后可以访问其值
Func<int> Example(int p1) {
return () => p1;
}
捕获变量的另一个属性是变量的变化在lambda表达式之外也是可见的。例如,以下打印42
void Example2(int p1) {
Action del = () => { p1 = 42; }
del();
Console.WriteLine(p1);
}
这两个属性产生一系列效果,它们以下列方式面对ref参数
这些属性有些不兼容,是lambda表达式中不允许使用它们的原因之一。
答案 1 :(得分:79)
在幕后,匿名方法是通过提升捕获的变量(这是你的问题主体所有)来实现的,并将它们存储为编译器生成的类的字段。无法将ref
或out
参数存储为字段。 Eric Lippert在a blog entry中对此进行了讨论。请注意,捕获的变量和lambda参数之间存在差异。你可以拥有如下所示的“形式参数”,因为它们不是捕获的变量:
delegate void TestDelegate (out int x);
static void Main(string[] args)
{
TestDelegate testDel = (out int x) => { x = 10; };
int p;
testDel(out p);
Console.WriteLine(p);
}
答案 2 :(得分:58)
您可以但必须明确定义所有类型
(a, b, c, ref d) => {...}
无效,但是
(int a, int b, int c, ref int d) => {...}
有效
答案 3 :(得分:5)
因为这是Google上“C#lambda ref”的最佳成绩之一;我觉得我需要扩展上面的答案。旧的(C#2.0)匿名委托语法有效,它确实支持更复杂的签名(以及闭包)。 Lambda和匿名委托至少在编译器后端共享感知实现(如果它们不相同) - 最重要的是,它们支持闭包。
我在搜索时尝试做的事情,以演示语法:
public static ScanOperation<TToken> CreateScanOperation(
PrattTokenDefinition<TNode, TToken, TParser, TSelf> tokenDefinition)
{
var oldScanOperation = tokenDefinition.ScanOperation; // Closures still work.
return delegate(string text, ref int position, ref PositionInformation currentPosition)
{
var token = oldScanOperation(text, ref position, ref currentPosition);
if (token == null)
return null;
if (tokenDefinition.LeftDenotation != null)
token._led = tokenDefinition.LeftDenotation(token);
if (tokenDefinition.NullDenotation != null)
token._nud = tokenDefinition.NullDenotation(token);
token.Identifier = tokenDefinition.Identifier;
token.LeftBindingPower = tokenDefinition.LeftBindingPower;
token.OnInitialize();
return token;
};
}
请记住,Lambdas在程序上和数学上更安全(因为前面提到的ref值促销):你可能会打开一堆蠕虫。使用这种语法时请仔细考虑。
答案 4 :(得分:0)
也许是这个?
private void Foo()
{
int value;
Bar(out value);
}
private void Bar(out int value)
{
value = 3;
int[] array = { 1, 2, 3, 4, 5 };
var val = value;
int newValue = array.Where(a => a == var).First();
}