문제

C#에서 자바(및뿐만 아니라 다른 언어로),변수를 선언에"시도"블록에 있지 않는 범위에서 해당 잡아""또는"마지막"니다.예를 들어,다음 코드를 컴파일되지 않습니다:

try {
  String s = "test";
  // (more code...)
}
catch {
  Console.Out.WriteLine(s);  //Java fans: think "System.out.println" here instead
}

이 코드를 컴파일 타임 오류가 발생한 참조하 s 에서 잡을 차단하기 때문에,s 만에서는 범위에서도 블록입니다.(자바에서 컴파일한 오류"s 확인할 수 없";C#에서의"이름이's'존재하지 않는 현재 상황에서".)

일반 솔루션이 이 문제할 수 있을 것 대신에 변수를 선언하기 전에 시도록,대신에도록:

String s;
try {
  s = "test";
  // (more code...)
}
catch {
  Console.Out.WriteLine(s);  //Java fans: think "System.out.println" here instead
}

그러나,적어도(1)이 같은 느낌 clunky 솔루션,그리고(2)그것은 결과는 변수에서 가장 큰 범위로 프로그래머 것(전체의 나머지 방법 대신만의 컨텍스트에서 try-캐치-마지막으로).

나의 질문은 무엇이었/는 이론적 근거(s)뒤에 이어 디자인 결정(Java,C#,그리고/또는 다른 적용 가능한 언어)?

도움이 되었습니까?

해결책

두 가지:

  1. 일반적으로,Java 는 2 개의 레벨의 범위:글로벌 및 기능입니다.하지만,try/잡은 제외(아 말장난).는 경우 예외가 발생하고 예외는 객체를 가져옵 변수를 할당하여,그 개체 변수에서만 사용할 수 있습니"잡을"섹션은 파괴로 캐치가 완료됩니다.

  2. (그리고 더 중요한 것은).당신이 알 수 없는 곳에 있도록 예외가 발생합니다.그것이 있었기 전에 변수를 선언했다.따라서 그것은 불가능하여 무엇을 말한 변수를 사용할 수 있다는 것 catch/마지막 절입니다.고려 다음과 같은 경우,범위는 당신이 제안:

    
    try
    {
        throw new ArgumentException("some operation that throws an exception");
        string s = "blah";
    }
    catch (e as ArgumentException)
    {  
        Console.Out.WriteLine(s);
    }
    

이것은 분명히 문제에 도달할 때는 예외 처리기,들 것이 없었을 선언했다.주어진을 잡는다는 의미를 처리하는 예외적인 상황 finallys 실행,안전하고 선언하는 이 문제를 컴파일 시간에 멀리보다 더 좋을 수 있습니다.

다른 팁

어떻게 당신이 될 수 있는 확실히,당신은 도달 선언부분에서 당신의 캐치 block?어떤 경우 인스턴스화가 발생한 예외?

전통적으로,에서는 C 스타일 언어,내부에 무슨 일이 중괄호 안에 머물 중괄호를 사용합니다.나는 생각을 갖는 평생의 변수에 걸쳐 스트레칭 범위는 다음과 같이 될 것입 비직관적이 가장 프로그래머를 위한 것입니다.를 달성할 수 있 당신이 원하는 무엇에 의해 둘러싸 try/catch/마지막으로 블록 안에의 다른 수준호하는 장치입니다.예:

... code ...
{
    string s = "test";
    try
    {
        // more code
    }
    catch(...)
    {
        Console.Out.WriteLine(s);
    }
}

편집:나는 모든 규칙 는 예외입니다.다음과 같은 유효한 C++:

int f() { return 0; }

void main() 
{
    int y = 0;

    if (int x = f())
    {
        cout << x;
    }
    else
    {
        cout << x;
    }
}

의 범위는 x 는 조건,다음 절은 그리고 다른 절입니다.

다른 사람들이 가져본적인에 무슨 블록에서 유지됩니다.그러나의 경우에.순,그것이 도움이 될 수 있습니다 무엇을 검사 컴파일러는 생각은 일어나고 있습니다.예를 들어,다음을 시도/catch 코드(주는 StreamReader 선언을 올바르게,외부 블록):

static void TryCatchFinally()
{
    StreamReader sr = null;
    try
    {
        sr = new StreamReader(path);
        Console.WriteLine(sr.ReadToEnd());
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
    finally
    {
        if (sr != null)
        {
            sr.Close();
        }
    }
}

이것은 컴파일을 다음과 같은 화면에서 MSIL:

.method private hidebysig static void  TryCatchFinallyDispose() cil managed
{
  // Code size       53 (0x35)    
  .maxstack  2    
  .locals init ([0] class [mscorlib]System.IO.StreamReader sr,    
           [1] class [mscorlib]System.Exception ex)    
  IL_0000:  ldnull    
  IL_0001:  stloc.0    
  .try    
  {    
    .try    
    {    
      IL_0002:  ldsfld     string UsingTest.Class1::path    
      IL_0007:  newobj     instance void [mscorlib]System.IO.StreamReader::.ctor(string)    
      IL_000c:  stloc.0    
      IL_000d:  ldloc.0    
      IL_000e:  callvirt   instance string [mscorlib]System.IO.TextReader::ReadToEnd()
      IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)    
      IL_0018:  leave.s    IL_0028
    }  // end .try
    catch [mscorlib]System.Exception 
    {
      IL_001a:  stloc.1
      IL_001b:  ldloc.1    
      IL_001c:  callvirt   instance string [mscorlib]System.Exception::ToString()    
      IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)    
      IL_0026:  leave.s    IL_0028    
    }  // end handler    
    IL_0028:  leave.s    IL_0034    
  }  // end .try    
  finally    
  {    
    IL_002a:  ldloc.0    
    IL_002b:  brfalse.s  IL_0033    
    IL_002d:  ldloc.0    
    IL_002e:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()    
    IL_0033:  endfinally    
  }  // end handler    
  IL_0034:  ret    
} // end of method Class1::TryCatchFinallyDispose

우리는 무엇을 볼 수 있습니까?MSIL 면 블록들이 본질적으로 일부의 기본 생성된 코드를 컴파일할 때는 C#.범위는 단지 하드 설정에서 C#spec,그것은에서 CLR 및 CLS spec 니다.

범위를 보호합니다 하지만 당신은 가끔 할 수 있습니다.시간에,당신은 그것을 사용하고,그것을 느끼기 시작한 자연합니다.다른 사람들처럼 말했다,무엇에서 일어나는 블록을 유지하는 블록입니다.당신이 뭔가를 공유하고 싶습니까?당신은 외부 블록을...

C++에서 어떤 속도,범위의 자동 변수에 의해 제한된 중괄호를 둘러싸고있는 그것.왜 사람이 다른 것에 의해 아래로 지불 시도하는 키워드는 외부 중괄호?

다음과 같 ravenspoint 지적,사람을 기대할 변수 지역을 정의합니다. try 을 소개하는 블록고 catch.

하려는 경우 지역 변수 모두 trycatch, 려고 둘러싸에서 두 블록:

// here is some code
{
    string s;
    try
    {

        throw new Exception(":(")
    }
    catch (Exception e)
    {
        Debug.WriteLine(s);
    }
}

간단한 대답은 C 그리고 대부분의 상속의 구문은 블록 범위입니다.는 것을 의미하는 경우는 변수에 정의된 한 블록,즉,내부{},그것은 그것의 범위가 있습니다.

예외 방법에 의해,자바스크립트는 유사한 구문을하지만,함수 범위입니다.에서 JavaScript,변수 선언서에 시험 구획에서는 범위에서,그리고 다른 곳에서 그것을 포함하는 기능입니다.

@유 문제를 가지고 있는 이유는 대답이 제대로 하지만 주고 싶었을 추가하는 동안,당신의 솔루션을 권장하는 예입니다 좋은 99.9999+%의 시간,그것은 좋지 않은 연습,그것은 훨씬 더 안전하거나 확인 null 을 사용하기 전에 뭔가 인스턴스화 내에서도 블록,또는 변수를 초기화하가 대신 그것을 선언하기 전에이다.예를 들어:

string s = String.Empty;
try
{
    //do work
}
catch
{
   //safely access s
   Console.WriteLine(s);
}

또:

string s;
try
{
    //do work
}
catch
{
   if (!String.IsNullOrEmpty(s))
   {
       //safely access s
       Console.WriteLine(s);
   }
}

이해야의 확장성을 제공합에서 해결 방법,그래서 그는 경우에도 당신이 무엇을 하고에서도 블록보다 더 복잡 할당 문자열 수 있어야 합 안전하게 데이터에 액세스하고 있습니다.

대답으로 모든 사람이 지은 거"그 방법은 블럭이 정의된".

거기에 몇 가지 제안하는 코드 예뻐합니다.보

 try (FileReader in = makeReader(), FileWriter out = makeWriter()) {
       // code using in and out
 } catch(IOException e) {
       // ...
 }

폐쇄 은 이뿐만 아니라.

with(FileReader in : makeReader()) with(FileWriter out : makeWriter()) {
    // code using in and out
}

업데이트: 팔로 구현되 Java7. http://download.java.net/jdk7/docs/technotes/guides/language/try-with-resources.html

에 따르면"부분하는 방법을 던지고 잡아 예외"에서 2 의 시작 자기 진행 훈련 장비(시험 70-536):Microsoft®.NET Framework2.0—응용 프로그램 개발 Foundation,그 이유는 예외가 발생했을 수 있기 전에 변수를 선언에서도 블록(다른 사람으로는 이미 주).

에서 견적은 25 페이지:

"주는 StreamReader 선언으로 이동했 밖에서도 블록에서 위의 예입니다.이 필요하기 때문에 마지막으로 블록에 액세스할 수 없는 변수를 선언에서도 블록입니다. 이것은 감지기 때문에 어디에 따라 예외가 발생한 변수 선언에서도 블록하지 않을 수 있었 실행."

당신 솔루션입니다 정확히 무엇을 해야 됩니다.당신이 될 수 없습니다 당신의 선언이었더라도에서 도달하려고 차단하는 것이 결과에서 또 다른 예외가 있습니다.

그것은 단순히 일해야로서 별도의 범위가 있습니다.

try
    dim i as integer = 10 / 0 ''// Throw an exception
    dim s as string = "hi"
catch (e)
    console.writeln(s) ''// Would throw another exception, if this was allowed to compile
end try

이 변수는 차단 수준 및 제한을 시도하거나고 있습니다.비슷한을 정의하는 변수는 경우 문입니다.이것의 생각한 상황이다.

try {    
    fileOpen("no real file Name");    
    String s = "GO TROJANS"; 
} catch (Exception) {   
    print(s); 
}

문자열하지 않을 것을 선언할 수 없습니다 그래서에 의존.

기 때문에 시도해 블록과 블록은 2 개의 다른 블록입니다.

다음 코드에서,당신은 기 s 에 정의된 블록에서 볼 수 있 block B?

{ // block A
  string s = "dude";
}

{ // block B
  Console.Out.WriteLine(s); // or printf or whatever
}

에서 특정 예를 들어 당신은 주어진 가장 큰 s 할 수 없습니다.그래서 당신이 생각하는 어쩌면 그 범위를 확장 할 수있다.

그러나 일반적으로,initialiser 표현할 수 있습 던지 예외가 있습니다.한다는 것은 적절하지 않은 변수의 initialiser 예외가 발생했습니다.(또는 후에 또 다른 변수가 일어났던)것을 범위에 대한 catch/마지막으로.

또한,코드 가독성을 겪을 것입니다.이 규칙에서는 C(그리고 언어를 따르는 포함하여 C++,Java,C#)는 간단하다:변수 범위를 따릅니다.

당신이 원하는 경우는 변수하는 범위에 대한 시도/catch/마지막으로 하지만 다른 곳,그 랩 전체에서 또 다른 설정의 중괄호(벌거벗은 블럭)및 변수를 선언하기 전에 시도합니다.

일부의 이유로 그들은 같은 범위에 있기 때문에서 어떤 시점의 시험을 차단할 수 있습 던진 예외입니다.는 경우 그들은 같은 범위에서,그 재난에서 기다리고 있기 때문에 어디에 따라 예외가 발생했습니다,그것은 더 많은 수지한다.

적어도 하면 그 선언의 외부에서도 블록,당신은 확실히 알고있는 어떤 변수 최소 될 수 있는 경우 예외가 발생;변수의 값을 하기 전에이다.

를 선언할 때 지역 변수에 배치되어 스택(대한 몇 가지 종류의 개체 스택에서,다른 유형 단지 참조할 스택에서).가있는 경우에는 예외 try 블록,지역 변수 내에서 블록 해방된 것을 의미하는 스택은"해제"다시 상태에서의 시작 부분에서도 블록입니다.이것은 의도적인 것입니다.그것은 얼마나 시도/잡을 수 있을 모두 함수 호출에 차단하는 시스템으로 다시 기능 상태가 됩니다.지 않고 이 메커니즘을 수 있는지 확인하는 것이 가능하의 국가도 예외가 발생합니다.

는 오류 처리 코드에 의존하고 외부적으로 선언된 변수는 그 값을 변경 내부 try 블록처럼 보인다 나쁜 디자인이다.당신이 무엇을 하고 있는 근본적으로 누출 의도적으로 자원을 얻기 위해서는 정보(이 특정한 경우에 그것은 그렇게 나쁘지 않기 때문에 당신은 단지 누수 정보를,그러나 상상할 경우 다른 자?당신이 그냥 생활이 어려워서 미래에 자신).내가 제안하는 것이 파괴하려는 블록으로 작은 덩어리가 필요한 경우 더 세분에서 오류를 처리합니다.

할 때도 잡아야에서 가장 부분을 알고는 오류를 수 있습니다.기관총 소리 응용 프로그램을 제외 수업과 함께 말해야 할 모든 것에 대한 예외는 아니다.하지 않을 경우,당신은 당신의 자신의 클래스를 제외하고 전달하는 정보와 함께.그런 식으로,당신은 필요하지 않을 얻을 변수 안에서 하려고 차단하기 때문에,이 예외는 자 explainatory.그래서 필요하신 경우에는 이렇게 많은지 생각해 당신을 디자인하고,생각하는 경우 몇 가지 다른 방법으로는 예측하는 예외를 오고가는 사용자 정보에서 나오는 예외를,그리고 아마를 다시 발생시키고 자신만의 예외는 자세한 정보를 확인할 수 있습니다.

으로 지적되었다,다른 사용자가 중괄호 정의 범위에서 꽤 많은 스타일의 모든 C 언어는 알고 있습니다.

는 경우 그것은 간단한 가변,다음 당신은 왜주는 것이 얼마나 되는 범위에서?그것은 큰입니다.

C#는 경우,그것은 복잡한 변수,구현하는 것이 좋습 IDisposable.할 수 있습니다 다음 사용하거나 시도/catch/마지막으로 호출 obj.폐기()에서 마지막으로 차단합니다.또는 사용할 수 있는 키워드를 사용하여 자동으로 호출 Dispose 의 끝 부분에 코드 섹션입니다.

파이썬에서 그들은 눈에 보이는 catch/마지막으로 블록하는 경우는 줄을 선언하지 않았습니다.

어떤 예외가 발생하는 경우에는 코드는 위의 선언 변수입니다.을 의미하는 선언이었지 않은 일이 생긴 경우에.

try {

       //doSomeWork // Exception is thrown in this line. 
       String s;
       //doRestOfTheWork

} catch (Exception) {
        //Use s;//Problem here
} finally {
        //Use s;//Problem here
}

는 동안에는 예상하는 작동하지 않고 이와 유사한 하나:

    try
    {
         //Code 1
         String s = "1|2";
         //Code 2
    }
    catch
    {
         Console.WriteLine(s.Split('|')[1]);
    }

이것이 원인을 잡을 던져 null 참조 예외는 경우에는 코드는 1 끊었다.는 동안 지금의 의미도/잡은 매우 잘 이해하고,이는 구석이 되는 경우 s 정의는 초기 값,그래서 그것은 이론 적이 null 이 될 수 있지만,공용 의미가 있는 것 같습니다.

다시 이를 이론적으로 고정을 허용하는 분리 정의(String s; s = "1|2";다),또는 다른 조건이지만,그것은 일반적으로 쉽게 단지 아니라고 말합니다.

또한,그것은 의미의 범위를 정의한 세계적으로 예외 없이,특히,지역 주민들은 마지막으로 {} 그들은 정의에서,모든 경우에.사소한 포인트,하지만점이다.

마지막으로,하기 위해서 당신이 원하는 무엇을 추가할 수 있습니다 설정한 부류의 주위에 시도 잡을 수 있습니다.게 당신이 원하는 범위를하지만 올에서 약간의 비용 가독성,하지만 너무 많이하지 않습니다.

{
     String s;
     try
     {
          s = "test";
          //More code
     }
     catch
     {
          Console.WriteLine(s);
     }
}

내 것이라고 생각기 때문에서 뭔가를 시도록 트리거한 예외는 네임스페이스 내용할 수 없는 신뢰할 수 있는 ie 참조 문자열's'에서는 원인이 될 수 있었 던져 또 하나의 예외는 아니다.

라면 그것을 던져하지 않은 컴파일하고,오류를 선언할 수 있습니 그것의 나머지 부분에 대한 방법을 다음,없을 것을 선언 그것은 단지 내에서도 범위가 있습니다.그것은 강요할 것을 명시적으로는 변수가 되어 존재하지 않 모델 예측제어 등을 다룬다.

면 우리는 무시한 범위 블록 문제에 대한 순간,컴파일러가 많은 일을 어렵게 하는 상황에서의 잘 정의 되지 않습니다.이것은 불가능하지 않,범위의 오류에도 힘 당신은,저자의 코드를 실현의 의미를 작성하는 코드(는 문자열은 null 일 수 있습니다 catch 블록).는 경우에 당신의 코드가 법적,의 경우에는 OutOfMemory 예외 들지 않도록 보장 할당되는 메모리 슬롯:

// won't compile!
try
{
    VeryLargeArray v = new VeryLargeArray(TOO_BIG_CONSTANT); // throws OutOfMemoryException
    string s = "Help";
}
catch
{
    Console.WriteLine(s); // whoops!
}

CLR(따라서 컴파일러)또한 변수를 초기화하기 전에 사용됩니다.Catch 차단시 그것을 보장 할 수 없습니다.

그래서 우리는 컴파일러와 함께하는 데 많은 작업을 수행하는 연습을 제공하지 않는 많은 혜택과 혼동하는 사람들이 그들을 인도하는 왜 시도/을 잡을 다르게 작동합니다.

에 더하여 일관성,의지 않을 수 있도록 아무것도 공상하고 준수하여 이미 설정된 범위를 의미에 사용되는 언어로,컴파일러와 CLR 을 제공할 수 있는 더 큰 보장 상태의 변수의 내부에 있습니다.그것은 존재하고 있 초기화됩니다.

언어 디자이너가 좋은 일을 다른 구조 잠금 문제와 범위를 잘 정의할 수 있는 쓰기 명확하게 코드입니다.

예:이 키워드 IDisposable 개체:

using(Writer writer = new Writer())
{
    writer.Write("Hello");
}

에 해당합니다:

Writer writer = new Writer();
try
{        
    writer.Write("Hello");
}
finally
{
    if( writer != null)
    {
        ((IDisposable)writer).Dispose();
    }
}

하는 경우 시도/catch/마지막으로,이해하기 어렵도 refactoring 또는 다른 소개 층의 간접으로의 중간 클래스는 캡슐화의 의미를 하려는 당신이 무엇을 수행할 수 있습니다.을 보지 않고 실제 코드,그것을 어렵게됩니다.

지역 변수 대신,공공 시설 될 수 있는 선언;또한 이것을 피해야 하는 다른 잠재적인 오류의 할당되지 않은 변수가 있습니다.public string S{얻;set;}

C#Spec (15.2)국"범위의 지역 변수는 일정한 선언에서 블록 ist 니다."

(에서 당신의 첫번째 예에서도 블록의 블록은"s"를 선포)

는 경우에 할당 작업이 실패하 catch 문이 있을 것이 null 참조 다시되지 않은 변수가 있습니다.

C#3.0:

string html = new Func<string>(() =>
{
    string webpage;

    try
    {
        using(WebClient downloader = new WebClient())
        {
            webpage = downloader.DownloadString(url);
        }
    }
    catch(WebException)
    {
        Console.WriteLine("Download failed.");  
    }

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