람다 식에 ref 또는 out 매개 변수를 사용할 수없는 이유는 무엇입니까?
오늘 오류가 발생하여 해결 방법을 찾았지만 이것이 왜 컴파일 타임 오류인지 궁금합니다.
CS1628 : 익명 메서드, 람다 식 또는 쿼리 식에서 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();
}
답변
람다는 변수의 수명을 변경하는 것처럼 보입니다. 예를 들어 다음과 람다 식의 파라미터 (P1)가 발생하지 사는 그 값있어서 프레임 이후에 액세스 될 수있는 스택에 더 이상 현재의 방법보다 긴 프레임
Func<int> Example(int p1) {
return () => p1;
}
캡처 된 변수의 또 다른 속성은 변수에 대한 변경 사항이 람다 식 외부에서도 볼 수 있다는 것입니다. 예를 들어 다음은 42 장입니다.
void Example2(int p1) {
Action del = () => { p1 = 42; }
del();
Console.WriteLine(p1);
}
이 두 속성은 다음과 같은 방법으로 ref 매개 변수의 얼굴을 날리는 특정 효과 세트를 생성합니다.
- ref 매개 변수는 고정 된 수명을 가질 수 있습니다. 지역 변수를 ref 매개 변수로 함수에 전달하는 것을 고려하십시오.
- 람다의 부작용은 ref 매개 변수 자체에서 볼 수 있어야합니다. 메소드와 호출자 모두에서.
이들은 다소 호환되지 않는 속성이며 람다 식에서 허용되지 않는 이유 중 하나입니다.
답변
후드 아래에서 익명 메소드는 캡처 된 변수 (질문 본문이 전부인 것)를 게양 하고이를 컴파일러 생성 클래스의 필드로 저장하여 구현됩니다. ref
또는 out
매개 변수를 필드로 저장하는 방법은 없습니다 . 에릭 리퍼 (Eric Lippert) 는 블로그 에서이를 언급했다 . 캡처 된 변수와 람다 매개 변수에는 차이가 있습니다. 변수가 캡처되지 않으므로 다음과 같은 “형식 매개 변수”를 가질 수 있습니다 .
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;
};
}
Lambdas는 절차 적으로 수학적으로 안전합니다 (앞서 언급 한 참조 값 승격 때문에). 웜 캔을 열 수 있습니다. 이 구문을 사용할 때는 신중하게 생각하십시오.
답변
그리고 아마도?
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();
}