C# & VB.NET2006. 3. 5. 17:56

C#에서는 try-catch-finally 구조를 사용해서 각 예외처리를 수행한다. 그런데 이 구조에서 예전에 제가 C#을 처음 익힐 때부터 약간 혼란스러웠던 것이 있다.


바로 Return 문이 어디에 위치해야 하는가이다...


MSDN 라이브러리의 try-catch-finally 구조에 대한 설명을 보자.

A common usage of catch and finally together is to obtain and use resources in a try block, deal with exceptional circumstances in a catch block, and release the resources in the finally block.

Catch finally같이 때의 일반적인 사용법은 try 블록에서 리소스를 얻어내서 사용하고, catch 블록에서는 예외적인 상황을 다루며, finally 블록에서리소스를 해제한다.



즉, return을 어디 두어야 하는 지는 어디에도 없다.

샘플도 교묘하게 void를 리턴 하는 함수를 만들어서 피해가고 있다.


두 가지 가설이 있을 수 있다.

첫 번째는 return은 메서드가 최종적으로 결과를 돌려주는 것이므로, finally 아래에 와야 한다.

두 번째는 try-catch-finally의 구조로 볼 때, return 문은 예외 처리 코드도 아니고 리소스 해제 코드도 아니기 때문에 try 내부에 오는 것이 맞다.

그래서 가지 방법으로 코드를 작성해 보았다.


//return문이 가장 마지막에 위치

public int ReturnInLastLine()

{

int i = 0;

PrivateOBJ obj = null;

try

{

obj = new PrivateOBJ();

i = obj.GetINT();

}

catch(Exception ex)

{

throw ex;

}

finally

{

obj = null;

}

return i;

}

//try블록 내부에 return이 위치

public int ReturnInTry()

{

int i = 0;

PrivateOBJ obj = null;

try

{

obj = new PrivateOBJ();

i = obj.GetINT();

           return i;

}

catch(Exception ex)

{

throw ex;

}

finally

{

obj = null;

}

}

그리고, 클래스를 컴파일한다음  .NET Reflector디스어셈블한 코드를 보았다.



결과는놀랍게도,

public int ReturnInLastLine()
{
int num1 = 0;
PrivateOBJ eobj1 = null;
try
{
eobj1 = new PrivateOBJ();
num1 = eobj1.GetINT();
}
catch (Exception exception1)
{
throw exception1;
}
finally
{
eobj1 = null;
}
return num1;
}

public int ReturnInTry()
{
int num2;
int num1 = 0;
PrivateOBJ eobj1 = null;
try
{
eobj1 = new PrivateOBJ();
num1 = eobj1.GetINT();

//여기 주의

//원 소스 코드에는 여기에 return이 있다. 그런데?
num2 = num1;
}
catch (Exception exception1)
{
throw exception1;
}
finally
{
eobj1 = null;
}

//여기에 리턴문이 있다.
return num2;
}


IL 코드도 이와 거의 유사하다고 보면 된다.

즉, return을 어느 위치에 두던지 간에 실제로 IL로 컴파일된 코드에서는 return이 가장 마지막에 위치한다는 것이다.

그래서 두 번째 try 내부에 리턴이 있는 경우를 보면 IL 코드는 내부적으로 (코드에는 없는) 변수를 하나
더 선언해서
거기에 값을 할당하고 그 변수를 최종적으로 리턴을 수행할 때 사용하는 것을 볼 수가 있다.



결론

1. 코드 상에서 return문이 어디에 있더라도, IL 코드 상에서는 가장 마지막 라인에 return문이 있게 된다. 결론적으로 마지막에 두는 것이 맞다는 것이다.

2. 코드에 Try 블록 혹은 catch 블록 혹은 여러 군데에 return을 위치시킬 수 있다. 심지어 if-else 문을 사용해서 각각 return하는 경우도 있다. (절대로 권장하지 않는 코딩방법!!) 그 경우 IL이 내부적으로 최종 리턴을 위해서 변수를 하나씩 더 할당한다. 이 값이 만약 매우 큰 데이터셋이라면? 메모리 누수의 원인이 될 수도 있을 듯 하다. 결과적으로 비효율적인 코드라는 것이고, 피해야 할 코딩이 되는 것이다.

Posted by kkongchi