Dlaczego nie możesz użyć parametru ref lub out w wyrażeniu lambda?
Natknąłem się dzisiaj na błąd i znalazłem obejście, ale nadal byłem ciekawy, dlaczego jest to błąd czasu kompilacji.
CS1628 : Nie można użyć w parametrze ref lub out „parametr” wewnątrz metody anonimowej, wyrażenia lambda lub wyrażenia zapytania
Oto prosty przykład:
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();
}
Odpowiedzi:
Lambdy wydają się zmieniać czas życia przechwytywanych zmiennych. Na przykład poniższe wyrażenie lambda powoduje, że parametr p1 żyje dłużej niż bieżąca ramka metody, ponieważ do jego wartości można uzyskać dostęp, gdy ramka metody nie znajduje się już na stosie
Inną właściwością przechwyconych zmiennych jest to, że zmiany w zmiennej są również widoczne poza wyrażeniem lambda. Na przykład następujące wydruki 42
Te dwie właściwości dają pewien zestaw efektów, które są sprzeczne z parametrem ref w następujący sposób
Są to nieco niezgodne właściwości i jeden z powodów, dla których są one niedozwolone w wyrażeniach lambda.
źródło
ref
wyrażenia lambda, ale chęć jego użycia nie została zaspokojona.Pod maską metoda anonimowa jest implementowana przez podnoszenie przechwyconych zmiennych (o to właśnie chodzi w treści pytania) i przechowywanie ich jako pól klasy wygenerowanej przez kompilator. Nie ma możliwości zapisania parametru
ref
lubout
jako pola. Eric Lippert omówił to we wpisie na blogu . Zwróć uwagę, że istnieje różnica między przechwyconymi zmiennymi a parametrami lambda. Państwo może mieć „parametrów formalnych” jak poniżej, ponieważ są one nie złapanych zmienne:źródło
Możesz, ale musisz jawnie zdefiniować wszystkie typy tak
Jest jednak nieważne
Jest ważna
źródło
ref
lubout
wewnątrz lambdy. Jest to jasne, jeśli przeczytasz przykładowy kod (spróbuj ponownie przeczytać go ponownie). Przyjęta odpowiedź jasno wyjaśnia dlaczego. Twoja odpowiedź dotyczy użycia parametruref
lub do lambda. Zupełnie nie odpowiadając na pytanie i mówiąc o czymś innymout
Ponieważ jest to jeden z najlepszych wyników dla „C # ref lambda” w Google; Czuję, że muszę rozwinąć powyższe odpowiedzi. Starsza (C # 2.0) składnia anonimowego delegata działa i obsługuje bardziej złożone podpisy (a także zamknięcia). Lambda i anonimowi delegaci przynajmniej współdzielili postrzeganą implementację w zapleczu kompilatora (jeśli nie są identyczni) - i co najważniejsze, obsługują zamknięcia.
Co próbowałem zrobić, gdy szukałem, aby zademonstrować składnię:
Pamiętaj tylko, że Lambdy są proceduralnie i matematycznie bezpieczniejsze (ze względu na wspomnianą wcześniej promocję wartości referencyjnej): możesz otworzyć puszkę robaków. Pomyśl uważnie, używając tej składni.
źródło
(a, b, c, ref d) => {...}
i zostałemref
podkreślony na czerwono z komunikatem o błędzie „Parametr '4' musi być zadeklarowany za pomocą słowa kluczowego 'ref'”. Facepalm! PS co to jest „promocja wartości referencyjnej”?A może to?
źródło