programing

try {return x; } 마지막으로 {x = null; } 문에서 실제로 어떤 일이 발생합니까?

starjava 2023. 5. 7. 10:44
반응형

try {return x; } 마지막으로 {x = null; } 문에서 실제로 어떤 일이 발생합니까?

저는 다른 질문에서 이 팁을 보고 도대체 어떻게 작동하는지 누가 설명해 줄 수 있는지 궁금했습니다.

try { return x; } finally { x = null; }

내 말은, 그게..finally조항은 정말로 다음에 실행됩니다.return진술서?이 코드는 얼마나 안전하지 않습니까?이것과 함께 할 수 있는 추가적인 해킹을 생각할 수 있습니까?try-finally해킹?

마지막 문이 실행되지만 반환 값은 영향을 받지 않습니다.실행 순서는 다음과 같습니다.

  1. 반품 전표 실행 전 코드
  2. 반품 전표식이 평가되었습니다.
  3. 마지막으로 차단이 실행됩니다.
  4. 2단계에서 평가한 결과가 반환됩니다.

다음은 시연을 위한 짧은 프로그램입니다.

using System;

class Test
{
    static string x;

    static void Main()
    {
        Console.WriteLine(Method());
        Console.WriteLine(x);
    }

    static string Method()
    {
        try
        {
            x = "try";
            return x;
        }
        finally
        {
            x = "finally";
        }
    }
}

이렇게 하면 "try"("try"("try"가 반환됨)가 인쇄되고 "finally"("finally")가 x의 새 값이기 때문입니다.

물론, 우리가 참조를 가변 객체(예: StringBuilder)로 반환하는 경우, 마지막 블록의 객체에 대한 변경 사항은 반환 시에 표시됩니다. 이는 반환 값 자체에 영향을 미치지 않습니다(참고일 뿐입니다).

아니오 - IL 수준에서는 예외 처리된 블록 내부에서 돌아올 수 없습니다.기본적으로 변수에 저장하고 나중에 반환합니다.

즉, 다음과 유사:

int tmp;
try {
  tmp = ...
} finally {
  ...
}
return tmp;

예(반사경 사용):

static int Test() {
    try {
        return SomeNumber();
    } finally {
        Foo();
    }
}

컴파일 대상:

.method private hidebysig static int32 Test() cil managed
{
    .maxstack 1
    .locals init (
        [0] int32 CS$1$0000)
    L_0000: call int32 Program::SomeNumber()
    L_0005: stloc.0 
    L_0006: leave.s L_000e
    L_0008: call void Program::Foo()
    L_000d: endfinally 
    L_000e: ldloc.0 
    L_000f: ret 
    .try L_0000 to L_0008 finally handler L_0008 to L_000e
}

이것은 기본적으로 로컬 변수를 선언합니다.CS$1$0000), 값을 변수에 배치한 다음(처리된 블록을 가리키며), 블록을 종료한 후 변수를 로드한 다음 반환합니다.Reflector는 이를 다음과 같이 렌더링합니다.

private static int Test()
{
    int CS$1$0000;
    try
    {
        CS$1$0000 = SomeNumber();
    }
    finally
    {
        Foo();
    }
    return CS$1$0000;
}

마지막 절은 반환 문 이후에 실행되지만 실제로 함수에서 반환되기 전에 실행됩니다.제 생각에 그것은 나사산 안전과는 거의 관련이 없습니다.이것은 해킹이 아닙니다. 마지막으로 시도 블록이나 캐치 블록에서 무엇을 하든 항상 실행됩니다.

Mark Gravell과 Jon Skeet가 제공한 답변에 추가하여 객체와 다른 참조 유형이 반환될 때 유사하게 동작하지만 몇 가지 차이점이 있다는 것을 유념하는 것이 중요합니다.

반환되는 "무엇"은 단순 유형과 동일한 논리를 따릅니다.

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        try {
            return ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
    }
}

반환되는 참조는 로컬 변수가 최종 블록에서 새 참조를 할당하기 전에 이미 평가되었습니다.

실행은 기본적으로 다음과 같습니다.

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        Exception CS$1$0000 = null;
        try {
            CS$1$0000 = ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
        return CS$1$0000;
    }
}

차이점은 사용자가 주의하지 않을 경우 예기치 않은 동작이 발생할 수 있는 개체의 속성/메소드를 사용하여 변형 가능한 유형을 수정할 수 있다는 것입니다.

class Test2 {
    public static System.IO.MemoryStream BadStream(byte[] buffer) {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
        try {
            return ms;
        } finally {
            // Reference unchanged, Referenced Object changed
            ms.Dispose();
        }
    }
}

try-return-final에 대해 고려해야 할 두 번째 사항은 "참조 기준"으로 전달된 매개 변수가 반환 후에도 여전히 수정될 수 있다는 것입니다.반환 값만 평가되고 반환 대기 중인 임시 변수에 저장되며, 다른 변수는 여전히 정상적인 방식으로 수정됩니다.out 매개 변수의 계약은 이러한 방식으로 최종 블록까지 수행되지 않을 수 있습니다.

class ByRefTests {
    public static int One(out int i) {
        try {
            i = 1;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 1000;
        }
    }

    public static int Two(ref int i) {
        try {
            i = 2;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 2000;
        }
    }

    public static int Three(out int i) {
        try {
            return 3;
        } finally {
            // This is not a compile error!
            // Return value unchanged, Store new value referenced variable
            i = 3000;
        }
    }
}

다른 흐름 구조체와 마찬가지로 "try-return-finally"도 그 자리를 차지하며 실제로 컴파일하는 구조체를 작성하는 것보다 더 깨끗한 코드를 허용할 수 있습니다.하지만 그것은 gotcha's를 피하기 위해 조심스럽게 사용되어야 합니다.

한다면x알 수 . 요점을 모르겠습니다.xnull이 때( 전에 에) 됩니다.x무효).

반환 시(반환 값이 결정된 후) 필드 값의 변경을 보장하려는 경우에만 이러한 현상이 발생하는 것을 확인할 수 있습니다.

언급URL : https://stackoverflow.com/questions/421797/what-really-happens-in-a-try-return-x-finally-x-null-statement

반응형