2009-09-02 33 views
125

Bir lambda ifadesinde neden bir ref veya out parametresi kullanamıyorsunuz?Lamdada ifadelerinde ref veya out parametresi kullanılamıyor

Bugün hatayla karşılaştım ve bir çözüm buldum, ancak bunun neden bir derleme zamanı hatası olduğunu merak ediyordum. İşte

basit örnek:

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(); 
} 
+10

Sana vardı geçici çözüm ne olduğunu sorabilir miyim geçerli mi bulundu mu? – Beatles1692

+0

Bu yineleyicilerle ilgili, ama bu yazıdaki aynı akıl yürütmenin çoğu (aynı zamanda Eric Lippert — tarafından o zaman dil tasarım ekibindedir) lambdas için geçerlidir:

cevap

94

Lambda'lar onlar yakalamak değişkenlerin ömrünü değişen bir görünüme sahip. Örneğin, aşağıdaki lambda ifade bahsedilen çerçeve artık yığında çekilen değişkenlerin diğer bir özelliği olduğunu

Func<int> Example(int p1) { 
    return() => p1; 
} 

sonra değeri erişilebilir olarak mevcut yöntem çerçevesinde daha uzun canlı parametre p1 neden olur Değişkendeki değişiklikler lambda ifadesinin dışında da görülür. Örneğin, aşağıdaki baskılar

void Example2(int p1) { 
    Action del =() => { p1 = 42; } 
    del(); 
    Console.WriteLine(p1); 
} 

Bu iki özellik 42

  • ref parametreleri sabit bir ömre sahip olabilir aşağıdaki yollarla bir ref parametresine karşı kalkan etkilerin belirli bir dizi üretir. Bir yerel değişkeni bir işleve bir ref parametresi olarak geçirmeyi düşünün. Lambdadaki yan etkilerin ref parametresinin kendisinde görünmesi gerekir. Hem yöntem içinde hem de arayanda.

Bunlar birebir uyuşmaz özelliklerdir ve lambda ifadelerinde izin verilmemesinin nedenlerinden biridir.

+6

Anlıyorum ki lambda ifadesi içinde 'ref' kullanamıyoruz, ama kullanma arzusu beslenmedi. . – zionpi

66

Kaputun altında, anonim yöntem yakalanan değişkenleri (sorunuzu vücut hakkında ne olan) kaldırma ve bir derleyicinin alanları olarak depolayarak uygulanmaktadır oluşturulan sınıf. ref veya out parametresini bir alan olarak kaydetmenin bir yolu yoktur. Eric Lippert bunu a blog entry'da tartıştı. Yakalanan değişkenler ve lambda parametreleri arasında bir fark olduğunu unutmayın. onlar değişkenleri yakalanan değildir gibi aşağıdaki gibi "resmi parametreleri" sahip olabilir:

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); 
} 
5

Bu, Google'da "C# lambda ref" için en iyi sonuçlardan biri olduğundan; Yukarıdaki cevapları genişletmem gerektiğini hissediyorum. Daha eski (C# 2.0) anonim delege sözdizimi çalışır ve daha karmaşık imzaları destekler (aynı zamanda kapanır). Lambda ve anonim delege en azından derleyici arka ucunda (özdeş olmasalar da) algılanan uygulamayı paylaştılar - ve en önemlisi, kapanmaları destekliyorlar. Sadece Lambda'lar (çünkü Daha önce de belirttiğimiz ref değeri promosyon) prosedür ve matematiksel güvenlidir akılda tutmak

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; 
     }; 
} 

: Ben yaptım sözdizimi göstermek için, arama yapmak için çalışıyordu ne

: Bir solucan konservesi açabilirsin. Bu sözdizimini kullanırken dikkatli düşün.

+3

Bence bu soruyu yanlış anladınız. Soru, lambda'nın kapsayıcı yönteminde ref/out değişkenlerine erişememesinin nedeni, _lambda'nın kendisinin neden başarısız değişkenleri içeremediğini değil. AFAIK'in ikincisi için iyi bir sebebi yoktur. Bugün bir lambda yazdım (a, b, c, ref d) => {...} 've" ref "hata mesajıyla kırmızı altı çizildi" Parametre '4 "' ref 'anahtar sözcüğüyle bildirilmelidir ". Facepalm! Not; "ref değeri promosyonu" nedir? – Qwertie

+1

@Qwertie Bunu tam bir parametreleme ile çalışmak için aldım, anlam, a, b, c ve d türlerini içerir ve çalışır. BenAdams cevabına bakın (orijinal soruyu yanlış anlamasa da). –

+0

@Qwertie Ben sadece bu noktanın yarısını kaldırdığımı düşünüyorum - asıl mesele, param paramın bir kapanışa yerleştirilmesinin riskli olabileceğiydi, ama sonradan verdiğim örnekte bunun gerçekleşmediğini fark ettim. Bunun bile derleneceğini biliyor muyum? –

39

Sen ancak açıkça böylece

(a, b, c, ref d) => {...} 

ancak

(int a, int b, int c, ref int d) => {...} 

geçersiz mi tüm türlerini tanımlamak olmalıdır da

+3

İlginç olsa da, bu soruya cevap vermiyor. Tekrar okumayı deneyin – edc65

+8

Yapıyor; soru neden olmasın; Cevap verebiliyor musun? –

+11

Yapmıyor; soru, bir lambda içinde * zaten tanımlanmış olan "ref" veya "dışarıda" mevcut bir değişkene * neden referans verememenizdir. Örnek kodu okursanız anlaşılır (tekrar okumak için tekrar deneyin). Kabul edilen cevap, nedenini açık bir şekilde açıklıyor. Cevabınız lamda için 'ref' veya' out' * parameter * kullanımı ile ilgilidir. Tamamen soruya cevap vermiyor ve başka bir şey hakkında konuşmuyor – edc65