![](/img/trans.png)
[英]How to use a ref parameter in a thread if "Error CS1628: Cannot use in ref or out parameter inside an anonymous method, lambda or query expression"?
[英]Cannot use ref or out parameter in lambda expressions
為什么不能在 lambda 表達式中使用 ref 或 out 參數?
我今天遇到了這個錯誤並找到了解決方法,但我仍然很好奇為什么這是一個編譯時錯誤。
CS1628 :不能在匿名方法、lambda 表達式或查詢表達式中使用 in 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();
}
Lambda 看起來會改變它們捕獲的變量的生命周期。 例如,下面的 lambda 表達式導致參數 p1 的生存時間比當前方法幀長,因為它的值可以在方法幀不再在堆棧上之后訪問
Func<int> Example(int p1) {
return () => p1;
}
捕獲變量的另一個屬性是變量的更改在 lambda 表達式之外也是可見的。 例如,下面的代碼打印出 42
void Example2(int p1) {
Action del = () => { p1 = 42; };
del();
Console.WriteLine(p1);
}
這兩個屬性會產生一組特定的效果,這些效果通過以下方式在ref
參數面前飛行:
ref
參數可能具有固定的生命周期。 考慮將局部變量作為ref
參數傳遞給函數。ref
參數本身上可見。 在方法中和調用者中。這些是有些不兼容的屬性,也是 lambda 表達式中不允許使用它們的原因之一。
在后台,匿名方法是通過提升捕獲的變量(這是您的問題主體的全部內容)並將它們存儲為編譯器生成的類的字段來實現的。 無法將ref
或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);
}
您可以,但您必須明確定義所有類型,以便
(a, b, c, ref d) => {...}
但是無效
(int a, int b, int c, ref int d) => {...}
已驗證
因為這是 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;
};
}
請記住,Lambda 在程序和數學上更安全(因為前面提到的 ref 值提升):您可能會打開一罐蠕蟲。 使用此語法時請仔細考慮。
也許這個?
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();
}
我再舉一個例子。
下面的代碼將拋出此錯誤。 因為 lambda 表達式(i)=>{...}
帶來的變化只在函數test
中有效。
static void test(out System.Drawing.Image[] bitmaps)
{
int count = 10;
bitmaps = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmaps[i] = System.Drawing.Image.FromFile("2.bmp");
});
}
因此,如果您out
參數,它就可以工作。
static void test(System.Drawing.Image[] bitmaps)
{
int count = 10;
bitmaps = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmaps[i] = System.Drawing.Image.FromFile("2.bmp");
});
}
如果out
需要,請不要直接更改 lambda 表達式中的參數。 相反,請使用臨時變量。
static void test(out System.Drawing.Image[] bitmaps)
{
int count = 10;
System.Drawing.Image[] bitmapsTemp = new System.Drawing.Image[count];
Parallel.For(0, count, (i) =>
{
bitmapsTemp[i] = System.Drawing.Image.FromFile("2.bmp");
});
bitmaps = bitmapsTemp;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.