2012-02-25 3 views
4

값을 반환하는 메서드가있는 경우 (예를 들어 Remove 메서드 Dictionary 클래스는 bool을 반환 함) 반환 값을 변수에 할당하지 않으면 어떻게됩니까? 즉, 결과를 bool 변수에 할당하지 않고 dictionary.Remove("plugin-01");을 작성하면 bool b = dictionary.Remove("plugin-01");과 관련하여 컴파일의 차이점은 무엇입니까?값을 반환하는 컴파일 된 메서드 호출은 어떻게됩니까?

답변

13

는 간단한 예제와는 LinqPad의 (의례를 생산하는 IL 코드를 살펴 보자 안전하게 쓸 수

if(!dictionary.Remove("plugin-01")) { 
    MessageBox.Show("Error: plugin-01 does not exist!"); 
} 

같은 뭔가를 할 수)

void Main() 
{ 
    Bar(); 
    Baz(); 
} 

bool Bar() 
{ 
    return true; 
} 

void Baz() 
{ 
    Console.WriteLine("placeholder"); 
} 

이 다음과 같은 IL를 생성합니다

IL_0000: ldarg.0  
IL_0001: call  UserQuery.Bar 
IL_0006: pop   //remove current value from evaluation stack 
IL_0007: ldarg.0  
IL_0008: call  UserQuery.Baz 


Bar: 
IL_0000: ldc.i4.1  
IL_0001: ret  

Baz: 
IL_0000: ldstr  "placeholder" 
IL_0005: call  System.Console.WriteLine 
IL_000A: ret 

Bar이 호출 된 다음 평가 스택에서 부울 반환 값을 제거하는 팝업이 있습니다. 아무 것도 없습니다. 예제를 업데이트하여 Baz()에 대한 다른 메서드 호출을 포함 시켜야만했습니다. 그렇지 않으면 프로그램이 끝나기 때문에 팝이 방출되지 않습니다.

void Main() 
{ 
    bool foo = Bar(); 
    Console.WriteLine(foo); 
} 

bool Bar() 
{ 
    return true; 
} 

이것은 다음과 같은 IL을 생성합니다 :

지금 우리가 실제로 반환 값을 사용하는 곳의는 경우를 살펴 보자

IL_0000: ldarg.0  
IL_0001: call  UserQuery.Bar 
IL_0006: stloc.0 //pops current value from evaluation stack, stores in local var 
IL_0007: ldloc.0  
IL_0008: call  System.Console.WriteLine 

Bar: 
IL_0000: ldc.i4.1  
IL_0001: ret 

모든 것을있는 System.Console.WriteLine 부분을 무시를 후 IL_007을 포함하여 - 컴파일러가 변수 사용을 최적화하지 않도록 추가해야했습니다. Bar 메서드 호출의 결과가 평가 스택에서 팝되어 로컬 변수 foo에 저장되는 것을 볼 수 있습니다. 차이점은 pop입니다. 반환 값을 가져 오거나 삭제하거나 stloc.0을 사용하여 결과를 변수에 할당 할 수 있습니다.

따라서 메서드 호출 결과가 필요하지 않으면 결과를 무시해야합니다. 결과를 변수에 할당하고 해당 변수를 사용하지 않더라도 컴파일러는 최소한 변수와 할당을 완전히 최적화 할 수 있습니다 (적어도 디버그 모드에서는 디버깅 환경을 개선하기 위해 대부분의 최적화가 비활성화 됨).

+0

'Console.WriteLine (foo)'를 제거하면 IL이 첫 번째 예제와 동일해야합니까? – enzom83

+1

예 - 그렇습니다. 변수'foo'가 사용되지 않았기 때문에 (아마) 최적화되었습니다. – BrokenGlass

+0

첫 번째 "다음 IL 생성"에서는 통화 다음에 오는 POP 명령을 포함시켜야한다고 생각합니다. 이것은 메소드 결과가 MSIL 스택에 있음을 명확히하고 호출자는 어떻게 든 처리해야합니다 (명시 적으로 "처리"한다고 명시 적으로 버리는 것을 의미 함). –

3

반환 값은 사용하지 않으면 무시됩니다. 당신은 상관하지 않는 경우

당신은

dictionary.Remove("plugin-01"); 
1

호출 부분은 동일하지만 할당 부분은 IL에서 건너 뜁니다. 봐 - 여기에 간단한 프로그램의 해체이다

var d = new Dictionary<int,int>(); 
bool a = d.Remove(5); 
d.Remove(6); 

디스 어셈블리는 다음과 같습니다

bool a = d.Remove(5); 
00000057 mov   ecx,dword ptr [ebp-40h] 
0000005a mov   edx,5 
0000005f cmp   dword ptr [ecx],ecx 
00000061 call  69106A00 
// Here is the assignment part 
00000066 mov   dword ptr [ebp-4Ch],eax 
00000069 movzx  eax,byte ptr [ebp-4Ch] 
0000006d mov   dword ptr [ebp-44h],eax 
    d.Remove(6); 
00000070 mov   ecx,dword ptr [ebp-40h] 
00000073 mov   edx,6 
00000078 cmp   dword ptr [ecx],ecx 
0000007a call  69106A00 

상위 4 선이 일반적이다가, 첫 번째 호출의 마지막 세 줄은 과제를 처리합니다. 그들은 두 번째 호출에 대한 해체에 빠져 있습니다.

관련 문제