C# 不能在 lambda 表达式中使用 ref 或 out 参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1365689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot use ref or out parameter in lambda expressions
提问by skalb
Why can't you use a ref or out parameter in a lambda expression?
为什么不能在 lambda 表达式中使用 ref 或 out 参数?
I came across the error today and found a workaround but I was still curious why this is a compile-time error.
我今天遇到了这个错误并找到了一个解决方法,但我仍然很好奇为什么这是一个编译时错误。
CS1628: Cannot use in ref or out parameter 'parameter' inside an anonymous method, lambda expression, or query expression
CS1628:不能在匿名方法、lambda 表达式或查询表达式中使用 in ref 或 out 参数“parameter”
Here's a simple example:
这是一个简单的例子:
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();
}
采纳答案by JaredPar
Lambdas have the appearance of changing the lifetime of variables that they capture. For instance the following lambda expression causes the parameter p1 to livelonger than the current method frame as its value can be accessed after the method frame is no longer on the stack
Lambda 的外观改变了它们捕获的变量的生命周期。例如,下面的 lambda 表达式导致参数 p1比当前方法帧存活的时间更长,因为它的值可以在方法帧不再在堆栈上之后被访问
Func<int> Example(int p1) {
return () => p1;
}
Another property of captured variables is that changes to the variable are also visible outside the lambda expression. For example the following prints 42
捕获变量的另一个特性是对变量的更改在 lambda 表达式之外也是可见的。例如以下打印 42
void Example2(int p1) {
Action del = () => { p1 = 42; }
del();
Console.WriteLine(p1);
}
These two properties produce a certain set of effects which fly in the face of a ref parameter in the following ways
这两个属性会产生一组特定的效果,这些效果以以下方式面对 ref 参数
- ref parameters may have a fixed lifetime. Consider passing a local variable as a ref parameter to a function.
- Side effects in the lambda would need to be visible on the ref parameter itself. Both within the method and in the caller.
- ref 参数可能有固定的生命周期。考虑将局部变量作为 ref 参数传递给函数。
- lambda 中的副作用需要在 ref 参数本身上可见。在方法内和调用者中。
These are somewhat incompatible properties and are one of the reasons they are disallowed in lambda expressions.
这些属性有些不兼容,并且是 lambda 表达式中不允许使用它们的原因之一。
回答by Mehrdad Afshari
Under the hood, the anonymous method is implemented by hoisting captured variables(which is what your question body is all about) and storing them as fields of a compiler generated class. There is no way to store a ref
or out
parameter as a field. Eric Lippert discussed it in a blog entry. Note that there is a difference between captured variables and lambda parameters. You canhave "formal parameters" like the following as they are not captured variables:
在幕后,匿名方法是通过提升捕获的变量(这是您的问题正文的全部内容)并将它们存储为编译器生成的类的字段来实现的。无法将 aref
或out
参数存储为字段。Eric Lippert 在一篇博客文章中对此进行了讨论。请注意,捕获的变量和 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);
}
回答by Jonathan Dickinson
As this is one of the top results for "C# lambda ref" on Google; I feel I need to expand on the above answers. The older (C# 2.0) anonymous delegate syntax works and it does support more complex signatures (as well closures). Lambda's and anonymous delegates at the very least have shared perceived implementation in the compiler backend (if they are not identical) - and most importantly, they support closures.
由于这是 Google 上“C# lambda ref”的最佳结果之一;我觉得我需要扩展上述答案。较旧的(C# 2.0)匿名委托语法有效,它支持更复杂的签名(以及闭包)。Lambda 和匿名委托至少在编译器后端共享了感知实现(如果它们不相同) - 最重要的是,它们支持闭包。
What I was trying to do when I did the search, to demonstrate the syntax:
当我进行搜索时,我想做什么来演示语法:
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;
};
}
Just keep in mind that Lambdas are procedurally and mathematically safer (because of the ref value promotion mentioned earlier): you might open a can of worms. Think carefully when using this syntax.
请记住,Lambda 在程序和数学上更安全(因为前面提到的 ref 值提升):您可能会打开一堆蠕虫。使用此语法时请仔细考虑。
回答by Ben Adams
You can but you must explicitly define allthe types so
您可以,但必须明确定义所有类型,以便
(a, b, c, ref d) => {...}
Is invalid, however
无效,但是
(int a, int b, int c, ref int d) => {...}
Is valid
已验证
回答by ticky
And maybe this?
也许这个?
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 == val).First();
}