람다 식에서 ref 또는 out 매개 변수를 사용할 수 없습니다 사용할 수 없습니다. 다음은 간단한 예입니다. private void

람다 식에 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();
}

답변