문제

익명의 방법에 대한 좋은 점은 호출 컨텍스트에 로컬 인 변수를 사용할 수 있다는 것입니다. 이것이 아웃 파라미터 및 기능 결과에 효과가없는 이유가 있습니까?

function ReturnTwoStrings (out Str1 : String) : String;
begin
  ExecuteProcedure (procedure
                    begin
                      Str1 := 'First String';
                      Result := 'Second String';
                    end);
end;

물론 매우 인공적인 예, 그러나 나는 이것이 유용한 상황에 처해있었습니다.

내가 이것을 컴파일하려고 할 때, 컴파일러는 그가 "기호를 캡처 할 수 없다"고 불평합니다. 또한이 작업을 시도했을 때 한 번 내부 오류가 발생했습니다.

편집하다 방금 정상적인 매개 변수에 효과가 있다는 것을 깨달았습니다.

... (List : TList)

다른 경우만큼 문제가되지 않습니까? 익명 방법이 실행될 때마다 참조가 여전히 살아있는 객체를 가리키고 있다고 누가 보장합니까?

도움이 되었습니까?

해결책

이 작업의 안전을 정적으로 확인할 수 없으므로 Var 및 Out 매개 변수 및 결과 변수를 캡처 할 수 없습니다. 결과 변수가 문자열 또는 인터페이스와 같은 관리 유형 인 경우, 스토리지는 실제로 발신자에 의해 할당 되며이 스토리지에 대한 참조는 암시 적 매개 변수로 전달됩니다. 다시 말해, 유형에 따라 결과 변수는 Out 매개 변수와 같습니다.

Jon이 언급 한 이유는 안전을 확인할 수 없습니다. 익명의 방법에 의해 생성 된 폐쇄는 그것이 생성 된 방법 활성화를 오래 살 수 있으며, 그 방법이 생성 된 방법의 활성화를 유사하게 유사하게 활성화 할 수 있습니다. 따라서 캡처 된 VAR 또는 출력 매개 변수 또는 결과 변수는 고아가 될 수 있으며, 미래의 폐쇄 내부의 글은 스택을 손상시킬 수 있습니다.

물론 Delphi는 관리되는 환경에서 실행되지 않으며 EG C#과 동일한 안전 제한이 없습니다. 언어는 당신이 원하는 것을 할 수 있습니다. 그러나 잘못된 상황에서 버그를 진단하기가 어렵습니다. 나쁜 행동은 눈에 띄는 근접 원인이없는 일상적인 변화 값의 로컬 변수로 나타납니다. 메소드 참조가 다른 스레드에서 호출되면 더 나빠질 것입니다.

이것은 디버그하기가 상당히 어려울 것입니다. 스택이 자주 수정되므로 하드웨어 메모리 브레이크 포인트조차도 비교적 열악한 도구입니다. 다른 중단 점 (예 : 메소드 입력시)에 조건부로 하드웨어 메모리 브레이크 포인트를 켜야합니다. 델파이 디버거는이 작업을 수행 할 수 있지만 대부분의 사람들 이이 기술에 대해 알지 못한다는 추측을 위험에 빠뜨릴 것입니다.

업데이트: 귀하의 질문에 대한 추가와 관련하여, 값으로 인스턴스 참조를 전달하는 의미는 폐쇄를 포함하는 메소드 (및 폐쇄를 포함하지 않는 Paramete0 및 메소드를 캡처합니다. 어느 쪽이든 메서드가 참조를 유지할 수 있습니다. 값으로 전달되는 인수; 매개 변수를 캡처하지 않는 메소드는 단순히 목록에 참조를 추가하거나 개인 필드에 저장할 수 있습니다.

발신자의 기대치가 다르기 때문에 상황은 참조별로 전달되는 매개 변수와 다릅니다. 이것을하는 프로그래머 :

procedure GetSomeString(out s: string);
// ...
GetSomeString(s);

GetSomestring이 s 변수가 통과되었습니다. 반면에 :

procedure AddObject(obj: TObject);
// ...
AddObject(TObject.Create);

그것은 놀라운 일이 아닙니다 AddObject 바로 그 이름은 매개 변수를 일부 상태의 매장에 추가하고 있음을 의미하기 때문에 참조를 유지합니다. 그 상태가 많은 매장이 폐쇄 형태인지 여부는 AddObject 방법.

다른 팁

문제는 STR1 변수가 returntwostrings에 의해 "소유"되지 않으므로 익명 메소드가 캡처 할 수 없다는 것입니다.

그것을 캡처 할 수없는 이유는 컴파일러가 궁극적 인 소유자를 알지 못하기 때문입니다 (returntwostrings를 호출하는 통화 스택 어딘가에있는 곳)는 어디에서 캡처 할 위치를 결정할 수 없기 때문입니다.

편집하다: (의견 후 추가 큰 타격)

익명 방법의 핵심은 변수를 캡처한다는 것입니다 (값이 아님).

Allen Bauer (Codegear)는 조금 더 설명합니다 ~에 대한 가변 캡처 그의 블로그에서.

이있다 C# 문제를 우회하는 것에 대한 질문 또한.

함수가 반환 된 후에 아웃 매개 변수와 반환 값은 관련이 없습니다. 캡처하고 나중에 실행하면 익명 방법이 어떻게 행동 할 것으로 예상됩니까? (특히, 익명 메소드를 사용하여 대의원을 생성하지만 실행하지 않으면 함수가 반환 된 시간에 따라 출력 매개 변수와 리턴 값이 설정되지 않습니다.)

아웃 매개 변수는 특히 어렵습니다. 나중에 나중에 대의원을 호출 할 때까지 Out 매개 변수 별칭이 존재하지 않을 수있는 변수입니다. 예를 들어, OUT 매개 변수를 캡처하고 익명 메소드를 반환 할 수 있다고 가정하지만 Out 매개 변수는 호출 함수의 로컬 변수이며 스택에 있습니다. 호출 방법이 대의원을 어딘가에 저장 한 후 반환 된 경우 (또는 반환) 대의원이 마침내 호출되면 어떻게 될까요? 아웃 매개 변수의 값이 설정되었을 때 어디에 쓸까요?

당신의 편집이 당신의 질문을 실제로 다르게 만들기 때문에 이것을 별도의 답변에 넣습니다.

고객에게 도착하기 위해 서두르면서 나중에이 답변을 연장 할 것입니다.

편집은 값 유형, 참조 유형 및 var, out, const 및 매개 변수 표시가 전혀 미치는 영향에 대해 다시 생각해야 함을 나타냅니다.

값 유형을 먼저 수행합시다.

값 유형의 값은 스택에 살고 있으며 사본-할당 동작이 있습니다. (나중에 예제를 포함 시키려고 노력할 것입니다).

매개 변수 표시가 없으면 메소드 (프로 시저 또는 함수)로 전달 된 실제 값은 메소드 내부의 해당 매개 변수의 로컬 값으로 복사됩니다. 따라서 메소드는 전달 된 값에서 작동하지 않고 사본에서 작동합니다.

var 또는 const가 있으면 사본이 발생하지 않습니다.이 방법은 전달 된 실제 값을 나타냅니다. VAR의 경우 실제 값을 변경할 수 있습니다. Const는 허용되지 않습니다. 아웃을 위해 실제 값을 읽을 수는 없지만 여전히 실제 값을 쓸 수 있습니다.

참조 유형의 값은 힙에 살고 있으므로, var, const 또는 매개 변수 표시가없는 경우에는 중요하지 않습니다. 무언가를 변경하면 힙의 값을 변경합니다.

참조 유형의 경우 매개 변수 표시가 없을 때 여전히 사본이 표시되지만 힙의 값을 가리키는 참조 사본입니다.

이것은 익명의 방법이 복잡해지는 곳입니다. 변수 캡처를 수행합니다. (배리는 아마도 이것을 더 잘 설명 할 수 있지만 시도해 볼 것입니다.) 편집 된 경우 익명 방법은 목록의 로컬 사본을 캡처합니다. 익명의 방법은 해당 로컬 사본에서 작동하며 컴파일러 관점에서 모든 것이 Dandy입니다.

그러나 편집의 요점은 '일반 매개 변수에 대해 작동하는 것'과 '익명 메소드가 실행될 때마다 참조가 여전히 살아있는 객체를 가리키고 있음을 보장하는 것'의 조합입니다.

익명 메소드를 사용하든 아니든 항상 참조 매개 변수의 문제입니다.

예를 들어 이것은 :

procedure TMyClass.AddObject(Value: TObject);
begin
  FValue := Value;
end;

procedure TMyClass.DoSomething();
begin
  ShowMessage(FValue.ToString());
end;

누군가가 복용량이라고 부를 때 FValue가 여전히 존재하는 인스턴스가 존재한다고 누가 보증합니까? 대답은 FValue의 인스턴스가 죽었을 때 복용량을 부르지 않음으로써 직접 보장해야한다는 것입니다. 편집에 대한 동일한 보류 : 기본 인스턴스가 죽었을 때 익명 방법을 호출해서는 안됩니다.

이것은 참조 계산 또는 쓰레기 수집 솔루션이 삶을 더 편하게 만드는 영역 중 하나입니다. 마지막 참조가 사라질 때까지 인스턴스가 살아남을 것입니다 (원래 예상했던 것보다 더 오래 살 수 있습니다!).

따라서 편집을 통해 귀하의 질문은 실제로 익명 방법에서 일반적으로 참조 유형 매개 변수 및 수명 관리를 사용하는 시사점으로 변경됩니다.

바라건대 내 대답이 당신이 그 지역에가는 데 도움이되기를 바랍니다.

-jeroen

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top