2012. 1. 6. 00:53

닷넷에서 Console.Write의 구조.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
안녕하세요. Geeks_Company입니다.

이포스팅은 닷넷에서 콘솔로 출력을 할때 어느 시점에서 ToString()이 호출되는가를 볼까 해서 적어 둡니다.

이곳에서 예시로 들을 것은 Double 타입을 줬을때, 어떻게 값이 출력이 되는가 입니다.

그럼 소스를 참조 하면서 설명하겠습니다.

이글에 제시된 소스는 마이크로 소프트 닷넷 4.0의 소스 코드중 일부를 인용한 것이며, 모든 저작권은 MS에 있음을 명시 합니다.

추후 저작권 관련되서 문제가 된다면 삭제 하겠습니다.

 일단 Console의 WriteLine의 함수의 모습입니다.

1 [HostProtection(SecurityAction.LinkDemand, UI=true)] 2 public static void WriteLine(double value) 3 { 4 Out.WriteLine(value); 5 }
위에서 Out은 무엇일까 추적 합니다.

1 public static TextWriter Out 2 { 3 [HostProtection(SecurityAction.LinkDemand, UI=true)] 4 get 5 { 6 if (_out == null) 7 { 8 InitializeStdOutError(true); 9 } 10 return _out; 11 } 12 }

TextWriter 이네요.

1 public virtual void WriteLine(double value) 2 { 3 this.Write(value); 4 this.WriteLine(); 5 } 

virtual 로 선언이 되어 있네요.

Write를 따라가 보면,

 1 public virtual void Write(double value) 2 { 3 this.Write(value.ToString(this.FormatProvider)); 4 }

 이러한 함수가 호출 됩니다.

1 public virtual void Write(string value) 2 { 3 if (value != null) 4 { 5 this.Write(value.ToCharArray()); 6 } 7 }  

 그럼 다시 함수 호출되는곳을 보면,
1 public virtual void Write(char[] buffer) 2 { 3 if (buffer != null) 4 { 5 this.Write(buffer, 0, buffer.Length); 6 } 7 } 

또 호출되는곳을 따라가보면, 

1 public virtual void Write(char[] buffer, int index, int count) 2 { 3 if (buffer == null) 4 { 5 throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); 6 } 7 if (index < 0) 8 { 9 throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); 10 } 11 if (count < 0) 12 { 13 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); 14 } 15 if ((buffer.Length - index) < count) 16 { 17 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); 18 } 19 for (int i = 0; i < count; i++) 20 { 21 this.Write(buffer[index + i]); 22 } 23 }

결국 Char을 순차적으로 출력 합니다.

그럼 Line을 붙이는 부분을 보겠습니다.

1 public virtual void WriteLine() 2 { 3 this.Write(this.CoreNewLine); 4 } 5   

이 Write을 추적하면,

 
1 public virtual void Write(char[] buffer) 2 { 3 if (buffer != null) 4 { 5 this.Write(buffer, 0, buffer.Length); 6 } 7 }

위에서 호출함 함수가 다시 호출됩니다.

즉 한줄 출력 역시, Char로 이뤄진 Array 입니다.
 
확인차 보면 이러합니다.

1 protected char[] CoreNewLine; 

결국 상속받은 객체에서 설정을 하여 출력을 시키게 되네요.

그외에 데이터 타입에 따라서 약간의 다른 로직이 적용되기도 하지만,

일반적으로 String 으로 변환을 한후, charArray로 넘어가는건 같습니다.


마지막으로 WriteLine String으로 받을 경우의 함수 입니다.

1 public virtual void WriteLine(string value) 2 { 3 if (value == null) 4 { 5 this.WriteLine(); 6 } 7 else 8 { 9 int length = value.Length; 10 int num2 = this.CoreNewLine.Length; 11 char[] destination = new char[length + num2]; 12 value.CopyTo(0, destination, 0, length); 13 switch (num2) 14 { 15 case 2: 16 destination[length] = this.CoreNewLine[0]; 17 destination[length + 1] = this.CoreNewLine[1]; 18 break; 19 20 case 1: 21 destination[length] = this.CoreNewLine[0]; 22 break; 23 24 default: 25 Buffer.InternalBlockCopy(this.CoreNewLine, 0, destination, length * 2, num2 * 2); 26 break; 27 } 28 this.Write(destination, 0, length + num2); 29 } 30 }  

이소스를 보면서 느끼는건, Double를 직접 넘겨주게 될 경우, Double 의 ToString을 호출하여 처리 하게 되지만,
Double의 ToString()을 던져주게 되면, TextWriter의 WriteLine에서 직접 String을 핸들링 하여 처리 하게 됩니다.

수행 속도 측면을 생각하면, ToString은 쓰나 안쓰나 동일하게 적용되지 않을까 생각 합니다.