메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

C# 팁 & 테크닉

한빛미디어

|

2004-03-30

|

by HANBIT

21,661

저자: Stephen Teilhet and Jay Hilyard, 번역 한동훈

원문 URL: http://www.ondotnet.com/lpt/a/4585

노트: O"Reilly는 프로그래밍 팁 & 테크닉을 쿡북(Cookbook) 즉, 요리책이라는 제목으로 출간하고 있으며, 각 절들은 요리법(Recipe)로 표시한다.

편집자 노트: 오늘 소개하는 문자열 변환과 예외 처리에 관한 두 가지 주제는 C# Cookbook에 포함된 수 많은 해결책 중에 일부에 불과하다. C# 언어에 대한 초보자나 숙련된 C# 프로그래머 모두 일상적으로 부딪히는 문제들에 대한 실질적인 해답을 C# Cookbook에서 발견하게 될 것이다.

요리법 2.13: Byte[] 배열로 반환된 문자열을 문자열로 변환하기

문제

FCL의 많은 메서드들은 string이 아닌 byte[] 배열로 값을 반환한다. 이러한 메서드 목록은 다음과 같다.

  • System.Net.Sockets.Socket.Receive
  • System.Net.Sockets.Socket.ReceiveFrom
  • System.Net.Sockets.Socket.BeginReceive
  • System.Net.Sockets.Socket.BeginReceiveFrom
  • System.Net.Sockets.NetworkStream.Read
  • System.Net.Sockets.NetworkStream.BeginRead
  • System.IO.BinaryReader.Read
  • System.IO.BinaryReader.ReadBytes
  • System.IO.FileStream.Read
  • System.IO.FileStream.BeginRead
  • System.IO.MemoryStream // Constructor
  • System.IO.MemoryStream.Read
  • System.IO.MemoryStream.BeginRead
  • System.Security.Cryptography.CryptoStream.Read
  • System.Security.Cryptography.CryptoStream.BeginRead
  • System.Diagnostics.EventLogEntry.Data


위 메서드들이 반환하는 byte[] 배열은 대부분 아스키(ASCII)나 유니코드(Unicode)로 인코딩된 문자들이 들어있다. byte[] 배열을 재조합해서 원본 문자열로 변환해야 한다.

해결책

아스키(ASCII) 값으로 구성된 byte 배열을 string으로 변환하기 위해 다음 메서드를 사용하자.

using System;
using System.Text;

public static string FromASCIIByteArray(byte[] characters)
{
    ASCIIEncoding encoding = new ASCIIEncoding( );
    string constructedString = encoding.GetString(characters);

    return (constructedString);
}

UTF-16으로 인코딩된 유니코드로 구성된 byte 배열을 문자열로 변환하기 위해 다음 메서드를 사용한다.

public static string FromUnicodeByteArray(byte[] characters)
{
    UnicodeEncoding encoding = new UnicodeEncoding( );
    string constructedString = encoding.GetString(characters);

    return (constructedString);
}

논의

ASCIIEncoding 클래스의 GetStrong 메서드는 byte 배열안에 저장된 7 비트 아스키 문자들을 문자열로 변환한다. 127 보다 큰 값은 문자 ?로 변환된다. ASCIIEncoding 클래스는 System.Text 네임스페이스에 있다. GetString 메서드는 다양한 인자들을 사용할 수 있는 다른 버전들도 갖고 있다. 이들 다른 버전들은 문자열의 전체나 일부를 아스키로 변환한 후 byte 배열의 지정된 범위에 결과를 저장한다.
GetString 메서드는 ASCII 문자로 구성된 바이트 배열을 문자열로 변환한다.

UnicodeEncoding 클래스의 GetString 메서드는 유니코드 문자를 16 비트 유니코드 값으로 변환한다. UnicodeEncoding 클래스는 System.Text 네임스페이스에 속한다. GetString 메서드는 유니코드 문자값으로 된 바이트 배열을 변환한 문자열을 반환한다.

참고

MSDN 도움말에서 "ASCIIEncoding 클래스"와 "UnicodeEncoding 클래스"를 참고한다.


요리법 5.6: Reflection을 통해 호출된 메서드가 던진 예외 처리하기

문제

리플렉션(reflection)을 사용하여 예외를 생성하는 메서드를 호출하고 있다. 이 메서드가 반환하는 진짜 예외 객체를 얻고, 그 정보를 이용해서 문제를 분석하고 해결하고 싶다.

해결책

진짜 예외와 그에 대한 정보는 MethodInfo.Invoke에서 던지는 TargetInvocationException의 InnerException 속성에서 알 수 있다.

논의

다음 예제는 리플렉션을 통해 호출된 메서드에서 발생한 예외를 처리하는 방법을 설명한다. 다음 예제의 Reflect 클래스는 리플렉션 클래스를 사용하여 정적 메서드 TestInvoke를 호출하는 ReflectionException이 있다.

using System;
using System.Reflection;

public class Reflect
{
    public void ReflectionException( )
    {
        Type reflectedClass = typeof(Reflect);
        try
        {
            MethodInfo methodToInvoke = reflectedClass.GetMethod("TestInvoke");

            if (methodToInvoke != null)
            {
                object oInvoke = methodToInvoke.Invoke(null, null);
            }
        }
        catch(Exception e)
        {
            Console.WriteLine("MESSAGE: " + e.Message);
            Console.WriteLine("SOURCE: " + e.Source);
            Console.WriteLine("TARGET: " + e.TargetSite);
            Console.WriteLine("STACK: " + e.StackTrace + "\r\n");
    
            if(e.InnerException != null)
            {
                Console.WriteLine( );
                Console.WriteLine("\t**** INNEREXCEPTION START ****");
                Console.WriteLine("\tTYPE THAT THREW EXCEPTION: " +
                                  reflectedClass.ToString( ));
                Console.WriteLine("\tINNEREXCEPTION MESSAGE: " +
                                  e.InnerException.Message);
                Console.WriteLine("\tINNEREXCEPTION SOURCE: " +
                                  e.InnerException.Source);
                Console.WriteLine("\tINNEREXCEPTION STACK: " +
                                  e.InnerException.StackTrace);
                Console.WriteLine("\tINNEREXCEPTION TARGETSITE: " +
                                  e.InnerException.TargetSite);
                Console.WriteLine("\t****  INNEREXCEPTION END  ****");
            }

            Console.WriteLine( );

            // Shows fusion log when assembly cannot be located
            Console.WriteLine(e.ToString( ));
        }
    }

    // Method to invoke via reflection
    public static void TestInvoke( )
    {
        throw (new Exception("Thrown from invoked method."));
    }
}

실행결과는 다음과 같다:(역자처럼 Mono를 사용하면 조금 다른 형태의 결과를 보게 된다)

MESSAGE: Exception has been thrown by the target of an invocation.
SOURCE: mscorlib
TARGET: System.Object InternalInvoke(System.Object, System.Reflection.BindingFlags,
    System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo,
    Boolean, System.Reflection.Assembly, Boolean)
STACK: at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj,
    BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture,
    Boolean isBinderDefault, Assembly caller, Boolean verifyAccess)
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj,
    BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture,
    Boolean verifyAccess)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr,
     Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Reflect.ReflectionException( ) in
     c:\book cs cookbook\code\test.cs:line 22

        **** INNEREXCEPTION START ****
        TYPE THAT THREW EXCEPTION: ClassLibrary1.Reflect
        INNEREXCEPTION MESSAGE: Thrown from invoked method.
        INNEREXCEPTION SOURCE: ClassLibrary1
        INNEREXCEPTION STACK: at ClassLibrary1.Reflect.TestInvoke( ) in
            C:\BOOK CS CookBook\code\Test.cs:line 49
          at ClassLibrary1.Reflect.TestInvoke( ) in
            C:\BOOK CS CookBook\code\Test.cs:line 49
        INNEREXCEPTION TARGETSITE: Void TestInvoke( )
        ****  INNEREXCEPTION END  ****

methodToInvoke.Invoke 메서드가 호출되면 TestInvoke 메서드가 호출되며, 연쇄적으로 예외를 던지게 된다. 외부 예외는 TargetInvocationException 예외를 던진다. 이것은 리플렉션을 통해 호출되는 객체가 예외를 던질때 일반적으로 발생되는 예외이다. CLR은 TargetInvocationException 객체의 InnerException 속성 안에 호출된 메서드가 던진 예외를 포함시킨다. 이렇게 호출된 메서드가 던진 예외는 보통의 Exception 형식의 예외이다. 내부 예외는 **** INNEREXCEPTION START **** 텍스트가 시작하는 부분부터 볼 수 있다.

이 텍스트에 더하여 코드는 e.ToString을 호출하여 예외 텍스트를 출력한다. ToString으로부터 출력된 텍스트는 다음과 같다:

System.Reflection.TargetInvocationException: Exception has been thrown by the target
of an invocation. ---> System.Exception: Thrown from invoked method.
   at ClassLibrary1.Reflect.TestInvoke( ) in
       C:\BOOK CS CookBook\code\Test.cs:line 49
   at ClassLibrary1.Reflect.TestInvoke( ) in
       C:\BOOK CS CookBook\code\Test.cs:line 49
   --- End of inner exception stack trace ---
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags
     invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean
     isBinderDefault, Assembly caller, Boolean verifyAccess)
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags
     invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean
     verifyAccess)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr,
     Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   atReflect.ReflectionException( ) in c:\book cs cookbook  
     \code\test.cs:line 22

ToString 메서드를 사용하는 것은 외부 예외 정보와 함께 각각의 내부 예외 정보들을 볼 수 있는 빠르고 간단한 방법이다.

참조

MSDN 도움말에서 "Type 클래스"와 "MethodInfo 클래스"를 참고한다.

Stephen Teilhet은 전기공학에서 학위를 받았으나 그 이후 윈도우 플랫폼용 소프트웨어를 작성하기 시작했다.
Jay Hilyard는 윈도우 플랫폼을 위한 응용 프로그램 개발을 10년 이상 해왔으며 현재는 닷넷을 적극적으로 지지하고 있다.
TAG :
댓글 입력
자료실

최근 본 상품0