ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: C# Cookbook

Cooking with C#

by Stephen Teilhet and Jay Hilyard

Related Reading

C# Cookbook
By Stephen Teilhet, Jay Hilyard

Editor's note: Converting strings and handling exceptions, two of the topics covered in depth in today's recipes, are just a few of the hundreds of solutions to specific problems included in C# Cookbook. Whether you're new to the C# language or an experienced C# programmer, C# Cookbook provides practical answers to the day-to-day questions you run up against.

Recipe 2.13: Converting a String Returned as a Byte[ ] Back into a String

Problem

Many methods in the FCL return a byte[] consisting of characters instead of a string. Some of these methods include:

In many cases, this byte[] might contain ASCII or Unicode encoded characters. You need a way to recombine this byte[] to obtain the original string.

Solution

To convert a byte array of ASCII values to a complete string, use the following method:

using System;
using System.Text;

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

    return (constructedString);
}

To convert a byte array of Unicode values (UTF-16 encoded) to a complete string, use the following method:

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

    return (constructedString);
}

Discussion

The GetString method of the ASCIIEncoding class converts 7-bit ASCII characters contained in a byte array to a string. Any value larger than 127 will be AND'ed with the value 127 and the resulting character value will be displayed in the string. For example, if the byte array contains the value 200, this value will be converted to 72, and the character equivalent of 72 ('H') will be displayed. The ASCIIEncoding class can be found in the System.Text namespace. The GetString method is overloaded to accept additional arguments as well. The overloaded versions of the method convert all or part of a string to ASCII and then store the result in a specified range inside a byte array.

The GetString method returns a string containing the converted byte array of ASCII characters.

The GetString method of the UnicodeEncoding class converts Unicode characters into 16-bit Unicode values. The UnicodeEncoding class can be found in the System.Text namespace. The GetString method returns a string containing the converted byte array of Unicode characters.

See Also

See the "ASCIIEncoding Class" and "UnicodeEncoding Class" topics in the MSDN documentation.

Recipe 5.6: Handling Exceptions Thrown from Methods Invoked via Reflection

Problem

Using reflection, you invoke a method that generates an exception. You want to obtain the real exception object and its information in order to diagnose and fix the problem.

Solution

The real exception and its information can be obtained through the InnerException property of the TargetInvocationException exception that is thrown by MethodInfo.Invoke.

Discussion

The following example shows how an exception that occurs within a method invoked via reflection is handled. The Reflect class contains a ReflectionException method that invokes the static TestInvoke method using the reflection classes as shown here:

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."));
    }
}

This code displays the following text:

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  ****

When the methodToInvoke.Invoke method is called, the TestInvoke method is called and subsequently throws an exception. The outer exception thrown is the TargetInvocationException exception; this is the generic exception thrown when a method invoked through reflection throws an exception. The CLR automatically wraps the original exception thrown by the invoked method inside of the TargetInvocationException object's InnerException property. In this case, the exception thrown by the invoked method is the generic Exception exception. This exception is shown after the section that begins with the text **** INNEREXCEPTION START ****.

In addition to this text, the code also calls e.ToString to print out the exception text. The text output from ToString is:

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

Using the ToString method is a quick and simple way of displaying the most relevant outer exception information along with the most relevant information for each inner exception.

See Also

See the "Type Class" and "MethodInfo Class" topics in the MSDN documentation.

Be sure to check back to this site in two weeks for more recipes from C# Cookbook. Recipes will cover how to obtain the HTML from a URL, and how to efficiently synchronize the reading and writing of a resource.

Stephen Teilhet has been working with the .NET platform since the pre-alpha version of the.NET 1.0 framework was being developed by Microsoft.

Jay Hilyard has been developing applications for the Windows platform for over 15 years and he currently works on the New Product Team at Newmarket International in Portsmouth, NH.


Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.