BUY THIS BOOK
Add to Cart

PDF $37.99

Safari Books Online

What is this?

Looking to Reprint or License this content?


C# Cookbook
C# Cookbook, Second Edition By Jay Hilyard, Stephen Teilhet
January 2006
Pages: 1184

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Numbers and Enumerations
Simple types are value types that are a subset of the built-in types in C#, although, in fact, the types are defined as part of the .NET Framework Class Library (.NET FCL). Simple types are made up of several numeric types and a bool type. These numeric types consist of a decimal type (decimal), nine integral types (byte, char, int, long, sbyte, short, uint, ulong, ushort), and two floating-point types (float, double). Table 1-1 lists the simple types and their fully qualified names in the .NET Framework.
Table 1-1: The simple data types
Fully qualified name
Alias
Value range
System.Boolean
bool
true or false
System.Byte
byte
0 to 255
System.SByte
sbyte
-128 to 127
System.Char
char
0 to 65535
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction
Simple types are value types that are a subset of the built-in types in C#, although, in fact, the types are defined as part of the .NET Framework Class Library (.NET FCL). Simple types are made up of several numeric types and a bool type. These numeric types consist of a decimal type (decimal), nine integral types (byte, char, int, long, sbyte, short, uint, ulong, ushort), and two floating-point types (float, double). Table 1-1 lists the simple types and their fully qualified names in the .NET Framework.
Table 1-1: The simple data types
Fully qualified name
Alias
Value range
System.Boolean
bool
true or false
System.Byte
byte
0 to 255
System.SByte
sbyte
-128 to 127
System.Char
char
0 to 65535
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining Approximate Equality Between a Fraction and Floating-Point Value
You need to compare a fraction with a value of type double or float to determine whether they are within a close approximation to each other. Take, for example, the result of comparing the expression 1/6 and the value 0.16666667. These seem to be equivalent, except that 0.16666667 is precise to only eight places to the right of the decimal point, and 1/6 is precise to the maximum number of digits to the right of the decimal point that the data type will hold.
To compare the approximate equality between a fraction and a floating-point value, verify that the difference between the two values is within an acceptable tolerance:
	using System;

	// Override that uses the System.Double.Epsilon value
	public static bool IsApproximatelyEqualTo(double numerator,
	                                          double denominator,
	                                          double dblValue)
	{
	    return IsApproximatelyEqualTo(numerator,
	         denominator, dblValue, double.Epsilon);
	}

	// Override that allows for specification of an epsilon value
	// other than System.Double.Epsilon
	public static bool IsApproximatelyEqualTo(double numerator,
	                                          double denominator, 
	                                          double dblValue, 
	                                          double epsilon)
	{
	    double difference = (numerator/denominator) - dblValue;

	    if (Math.Abs(difference) < epsilon)
	    {
	        // This is a good approximation.
	        return true;
	    }
	    else
	    {
	        // This is NOT a good approximation.
	        return false;
	    }
	}
Replacing the type double with float allows you to determine whether a fraction and a float value are approximately equal.
Fractions can be expressed as a numerator over a denominator; however, storing them as a floating-point value might be necessary. Storing fractions as floating-point values introduces rounding errors that make it difficult to perform comparisons. Expressing the value as a fraction (e.g., 1/6) allows the maximum precision. Expressing the value as a floating-point value (e.g., 0.16667) can limit the precision of the value. In this case, the precision depends on the number of digits that the developer decides to use to the right of the decimal point.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Degrees to Radians
When using the trigonometric functions of the Math class, all units are in radians. You have one or more angles measured in degrees and want to convert these to radians in order to use them with the members of the Math class.
To convert a value in degrees to radians, multiply it by π/180:
	using System;

	public static double ConvertDegreesToRadians (double degrees)
	{
	    double radians = (Math.PI / 180) * degrees;
	    return (radians);
	}
All of the static trigonometric methods in the Math class use radians as their unit of measure for angles. It is very handy to have conversion routines to convert between radians and degrees, especially when a user is required to enter data in degrees rather than radians. After all, humans understand degrees better than radians.
The equation for converting degrees to radians is shown here:
	radians = (Math.PI / 180) * degrees
The static field Math.PI contains the constant π.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Radians to Degrees
When using the trigonometric functions of the Math class, all units are in radians; instead, you require a result in degrees.
To convert a value in radians to degrees, multiply it by 180/π:
	using System;

	public static double ConvertRadiansToDegrees(double radians)
	{
	    double degrees = (180 / Math.PI) * radians;
	    return (degrees);
	}
All of the static trigonometric methods in the Math class use radians as their unit of measure for angles. It is very handy to have conversion routines to convert between radians and degrees; displaying degrees to a user is more informative than displaying radians.
The equation for converting radians to degrees is shown here:
	degrees = (180 / Math.PI) * radians
The static field Math.PI contains the constant π.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using the Bitwise Complement Operator with Various Data Types
The bitwise complement operator (~) is overloaded to work directly with int, uint, long, ulong, and enumeration data types consisting of the underlying types int, uint, long, and ulong. However, you need to perform a bitwise complement operation on a different numeric data type.
To use the bitwise complement operator with any data type, you must cast the resultant value of the bitwise operation to the type you wish to work with. The following code demonstrates this technique with the byte data type:
	byte y = 1;
	byte result = (byte)~y;
The value assigned to result is 254.
The following code shows incorrect use of the bitwise complement operator on the byte data type:
	byte y = 1;
	Console.WriteLine("~y = " + ~y);
This code outputs the following surprising value:
	-2
Clearly, the result from performing the bitwise complement of the byte variable is incorrect; it should be 254. In fact, byte is an unsigned data type, so it cannot be equal to a negative number. If you rewrite the code as follows:
	byte y = 1;
	byte result = ~y;
you get a compile-time error: "Cannot implicitly convert type 'int' to 'byte.'" This error message gives some insight into why this operation does not work as expected. To fix this problem, you must explicitly cast this value to a byte before you assign it to the result variable, as shown here:
	byte y = 1;
	byte result = (byte)~y;
This cast is required because the bitwise operators are overloaded to operate on only six specific data types: int, uint, long, ulong, bool, and enumeration data types. When one of the bitwise operators is used on another data type, that data type is converted to the supported data type that matches it most closely. Therefore, a byte data type is converted to an int before the bitwise complement operator is evaluated:
	      0x01 // byte y = 1;
	0xFFFFFFFE // The value 01h is converted to an int and its
	           // bitwise complement is taken.
	           // This bit pattern equals -2 as an int.
	      0xFE // The resultant int value is cast to its original byte data type.
Notice that the int data type is a signed data type, unlike the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing for an Even or Odd Value
You need a simple method to test a numeric value to determine whether it is even or odd.
The solution is actually implemented as two methods. To test for an even integer value, use the following method:
	public static boolIsEven(int intValue)
	{
	    return ((intValue % 2) == 0);
	}
To test for an odd integer value, use the following method:
	public static boolIsOdd(int intValue)
	{
	    return ((intValue % 2) == 1);
	}
Every odd number always has its least-significant bit set to 1. Therefore, by checking whether this bit is equal to 1, you can tell whether it is an odd number. Conversely, testing the least-significant bit to see whether it is 0 can tell you whether it is an even number.
To test whether a value is even, you AND the value in question with 1 and then determine whether the result is equal to zero. If it is, you know that the value is an even number; otherwise, the value is odd. This operation is part of the IsEven method.
On the other hand, you can determine whether a value is odd by ANDing the value with 1, similar to how the even test operates, and then determine whether the result is 1. If so, you know that the value is an odd number; otherwise, the value is even. This operation is part of the IsOdd method.
Note that you do not have to implement both the IsEven and IsOdd methods in your application, although implementing both methods might improve the readability of your code. You can implement one in terms of the other. For example, here is an implementation of IsOdd in terms of IsEven:
	public static bool IsOdd(int intValue)
	{
	    return (!IsEven(intValue));
	}
The methods presented here accept only 32-bit integer values. To allow this method to accept other numeric data types, you can simply overload it to accept any other data types that you require. For example, if you need to also determine whether a 64-bit integer is even, you can modify the IsEven method as follows:
	public static bool IsEven(long longValue)
	{
	    return ((longValue & 1) == 0);
	}
Only the data type in the parameter list needs to be modified.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Obtaining the High Word or Low Word of a Number
You have a 32-bit integer value that contains information in both its lower and upper 16 bits. You need methods to get the high word (first 16 bits) and/or the low word (last 16 bits) of this value.
To get the high word of an integer value, perform a bit-wise AND between it and the value, as shown in the following method:
	public static intGetHighWord(int intValue)
	{
	    return (intValue & (0xFFFF << 16));
	}
To get the low word of a value, use the following method:
	public static intGetLowWord(int intValue)
	{
	    return (intValue & 0x0000FFFF);
	}
This technique can easily be modified to work with other sizes of integers (e.g., 8-bit, 16-bit, or 64-bit); this trick is shown in the Discussion section.
In order to determine the values of the high word of a number, use the following bit-wise AND operation:
	uint intValue = Int32.MaxValue;
	uint MSB = intValue & (0xFFFF << 16);

	// MSB == 0xFFFF0000
This method simply ANDs the number to another number with all of the high word set to 1. This method will zero out all of the low word, leaving the high word intact.
In order to determine the values of the low word of a number, use the following bitwise AND operation:
	uint intValue = Int32.MaxValue;
	uint LSB = intValue & 0x0000FFFF;

	// LSB == 0x0000FFFF
This method simply ANDs the number to another number with all of the low word set to 1, which zeros out all of the high word, leaving the low word intact.
The methods presented here accept only 32-bit integer values. To allow this method to accept other numeric data types, you can simply overload this method to accept any other data types that you require. For example, if you need to also acquire the low or high byte of a 16-bit integer, you can use the same structure as the GetHighWord method as follows:
	public static short GetHighByte(short shortValue)
	{
	    return (short)(shortValue & (0xFF << 8));
	}
The GetLowWord method is modified as shown here:
	public static short GetLowByte(short shortValue)
	{
	    return (short)(shortValue & (short)0xFF);
	}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting a Number in Another Base to Base10
You have a string containing a number in base2 (binary), base8 (octal), base10 (decimal), or base16 (hexadecimal). You need to convert this string to its equivalent integer value and display it in base10.
To convert a number in another base to base10, use the overloaded static Convert.ToInt32 method on the Convert class:
	string base2 = "11";
	string base8 = "17";
	string base10 = "110";
	string base16 = "11FF";

	Console.WriteLine("Convert.ToInt32(base2, 2) = " +
	                   Convert.ToInt32(base2, 2));

	Console.WriteLine("Convert.ToInt32(base8, 8) = " +
	                   Convert.ToInt32(base8, 8));

	Console.WriteLine("Convert.ToInt32(base10, 10) = " +
	                   Convert.ToInt32(base10, 10));

	Console.WriteLine("Convert.ToInt32(base16, 16) = " +
	                   Convert.ToInt32(base16, 16));
This code produces the following output:
	Convert.ToInt32(base2, 2) = 3
	Convert.ToInt32(base8, 8) = 15
	Convert.ToInt32(base10, 10) = 110
	Convert.ToInt32(base16, 16) = 4607
The static Convert.ToInt32 method has an overload that takes a string containing a number and an integer defining the base of this number. This method then converts the numeric string into an integer. Console.WriteLine then converts the number to base10 and displays it.
The other static methods of the Convert class, such as ToByte, ToInt64, and ToInt16, also have this same overload, which accepts a number as a string and the base in which this number is expressed. Unfortunately, these methods convert from a string value expressed in base2, base8, base10, and base16 only. They do not allow for converting a value to a string expressed in any other base types than base10. However, the ToString methods on the various numeric types do allow for this conversion.
See the "Convert Class" and "Converting with System.Convert" topics in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining Whether a String Is a Valid Number
You have a string that possibly contains a numeric value. You need to know whether this string contains a valid number.
Use the static TryParse method of any of the numeric types. For example, to determine whether a string contains a double, use the following method:
	    string str = "12.5";
	    double result = 0;
	    if(double.TryParse(str,
	            System.Globalization.NumberStyles.Float,
	            System.Globalization.NumberFormatInfo.CurrentInfo,
	            out result))
	    {

	        // Is a double!
	    }
This recipe shows how to determine whether a string contains only a numeric value. The TryParse method returns true if the string contains a valid number without the exception that you will get if you use the Parse method. Since TryParse does not throw exceptions, it performs better over time given a set of strings where some do not contain numbers.
See the "Parse" and "TryParse" topics in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Rounding a Floating-Point Value
You need to round a number to a whole number or to a specific number of decimal places.
To round any number to its nearest whole number, use the overloaded static Math.Round method, which takes only a single argument:
	int x = (int)Math.Round(2.5555); // x == 3
If you need to round a floating-point value to a specific number of decimal places, use the overloaded static Math.Round method, which takes two arguments:
	decimal x = Math.Round(2.5555, 2); // x == 2.56
The Round method is easy to use; however, you need to be aware of how the rounding operation works. The Round method follows the IEEE Standard 754, section 4 standard. This means that if the number being rounded is halfway between two numbers, the Round operation will always round to the even number. An example will show what this means to you:
	decimal x = Math.Round(1.5); // x == 2
	decimal y = Math.Round(2.5); // y == 2
Notice that 1.5 is rounded up to the nearest even whole number and 2.5 is rounded down to the nearest even whole number. Keep this in mind when using the Round method.
See Recipes 1.1 and 1.22; see the "Math Class" topic in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Choosing a Rounding Algorithm
The Math.Round method will round the value 1.5 to 2; however, the value 2.5 will also be rounded to 2 using this method. You may always want to round to the greater number in this type of situation (e.g., round 2.5 to 3 instead of 2). Conversely, you might want to always round to the lesser number (e.g., round 1.5 to 1).
Use the static Math.Floor method to always round up when a value is halfway between two whole numbers:
	public static double RoundUp(double valueToRound)
	{
	    return (Math.Floor(valueToRound + 0.5));
	}
Use the following technique to always round down when a value is halfway between two whole numbers:
	public static double RoundDown(double valueToRound)
	{
	    double floorValue = Math.Floor(valueToRound);
	    if ((valueToRound - floorValue) > .5)
	    {
	        return (floorValue + 1);
	    }
	    else
	    {
	        return (floorValue);
	    }
	}
The static Math.Round method rounds to the nearest even number (see Recipe 1.9 for more information). However, there are some times that you do not want to round a number in this manner. The static Math.Floor method can be used to allow for different manners of rounding.
Note that the methods used to round numbers in this recipe do not round to a specific number of decimal points; rather, they round to the nearest whole number.
See Recipes 1.9 and 1.22; see the "Math Class" topic in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Celsius to Fahrenheit
You have a temperature reading measured in Celsius and need to convert it to Fahrenheit.
	public static double CtoF(double celsius)
	{
	   return (((0.9/0.5) * celsius) + 32);
	}
To generate a double result while maintaining the same ratio (9 to 5) as the integers give, 0.9 and 0.5 are used in the calculation.
This recipe makes use of the following Celsius-to-Fahrenheit temperature conversion equation:
	TempFahrenheit = ((9 / 5) * TempCelsius) + 32
The Fahrenheit temperature scale is widely used in the United States. However, much of the rest of the world uses the Celsius temperature scale.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Fahrenheit to Celsius
You have a temperature reading measured in Fahrenheit and need to convert it to Celsius.
	public static double FtoC(double fahrenheit)
	{
	    return ((0.5/0.9) * (fahrenheit - 32));
	}
This recipe makes use of the following Fahrenheit-to-Celsius temperature conversion equation:
	TempCelsius = (5 / 9) * (TempFahrenheit - 32)
The Fahrenheit temperature scale is widely used in the United States. However, much of the rest of the world uses the Celsius temperature scale.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Safely Performing a Narrowing Numeric Cast
You need to cast a value from a larger value to a smaller one, while gracefully handling conditions that result in a loss of information. For example, casting a long to an int results in a loss of information only if the long data type is greater than int.MaxSize.
The simplest way to do this check is to use the checked keyword. The following method accepts two long data types and attempts to add them together. The result is stuffed into an int data type. If an overflow condition exists, the OverflowException is thrown:
	using System;

	public void UseChecked(long lhs, long rhs)
	{
	    int result = 0;

	    try
	    {
	        result = checked((int)(lhs + rhs));
	    }
	    catch (OverflowException e)
	    {
	        // Handle overflow exception here.
	    }
	}
This is the simplest method. However, if you do not want the overhead of throwing an exception and having to wrap a lot of code in try/catch blocks to handle the overflow condition, you can use the MaxValue and MinValue fields of each type. A check using these fields can be done prior to the conversion to insure that no loss of information occurs. If this does occur, the code can inform the application that this cast will cause a loss of information. You can use the following conditional statement to determine whether sourceValue can be cast to a short without losing any information:
	// Our two variables are declared and initialized.
	int sourceValue = 34000;
	short destinationValue = 0;

	// Determine if sourceValue will lose information in a cast to a short.
	if (sourceValue <= short.MaxValue && sourceValue >= short.MinValue)
	{
	    destinationValue = (short)sourceValue;
	}
	else
	{
	    // Inform the application that a loss of information will occur.
	}
A narrowing conversion occurs when a larger type is cast down to a smaller type. For instance, consider casting a value of type Int32 to a value of type Int16. If the Int32 value is smaller than or equal to the Int16.MaxValue field and the Int32 value is higher than or equal to the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Finding the Length of Any Three Sides of a Right Triangle
You need to calculate the length of one side of a triangle when either the lengths of two sides are known or one angle and the length of a side are known.
Use the Math.Sin, Math.Cos, and Math.Tan methods of the Math class to find the length of one side. The equations for these methods are as follows:
	double theta = 40;
	doublehypotenuse = 5;
	double oppositeSide = 0;
	double adjacentSide = 0;
	oppositeSide = Math.Sin(theta) * hypotenuse;
	oppositeSide = Math.Tan(theta) * adjacentSide;
	adjacentSide = Math.Cos(theta) * hypotenuse;
	adjacentSide = oppositeSide / Math.Tan(theta);
	hypotenuse = oppositeSide / Math.Sin(theta);
	hypotenuse = adjacentSide / Math.Cos(theta);
where theta (Θ) is the known angle, the oppositeSide variable is equal to the length of the side opposite to the angle theta, and the adjacentSide variable is equal to the length of the side adjacent to the angle theta. The hypotenuse variable is equal to the length of the hypotenuse of the triangle. See Figure 1-1.
Figure 1-1: A right triangle
In addition to these three static methods, the length of the hypotenuse of a right triangle can be calculated using the Pythagorean theorem. This theorem states that the hypotenuse of a right triangle is equal to the square root of the sum of the squares of the other two sides. This equation can be realized using the Math.Sqrt static method, as follows:
	double hypotenuse = Math.Sqrt((xSide * xSide) + (ySide * ySide));
where xSide and ySide are the lengths of the two sides that are not the hypotenuse of the triangle.
Finding the length of a side of a right triangle is easy when an angle and the length of one of the sides are known. Using the trigonometric functions sine, cosine, and tangent, you can derive the lengths of either of the two unknown sides. The equations for sine, cosine, and tangent are defined here:
	sin(Theta) = oppositeSide / hypotenuseSide
	cos(Theta) = adjacentSide / hypotenuseSide
	tan(Theta) = oppositeSide / adjacentSide
where theta is the value of the known angle. Rearranging these equations allows you to derive the following equations:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Finding the Angles of a Right Triangle
You need to calculate an angle of a triangle when the lengths of two sides are known.
Use the Math.Atan, Math.Acos, or Math.Asin static methods of the Math class. The following code calculates the angle theta and returns the value in radians:
	double theta = Math.Atan(OppositeSide / AdjacentSide);
	theta = Math.Acos(AdjacentSide / Hypotenuse);
	theta = Math.Asin(OppositeSide / Hypotenuse);
To get the angle in degrees, use the following code:
	double theta = Math.Atan(oppositeSide / adjacentSide) * (180 / Math.PI);
	theta = Math.Acos(adjacentSide / hypotenuse) * (180 / Math.PI);
	theta = Math.Asin(oppositeSide / hypotenuse) * (180 / Math.PI);
where theta is the known angle value, oppositeSide is equal to the length of the side opposite to the angle, and adjacentSide is equal to the length of the side adjacent to the angle. The hypotenuse is the length of the hypotenuse of the triangle. See Figure 1-1 in Recipe 1.14 for a graphical representation of these sides of a right triangle and Recipes 1.2 and 1.3 for converting between degrees and radians.
In some cases, you need to determine an angle of a right triangle when only the lengths of two sides are known. The three trigonometric functions arcsine, arccosine, and arctangent allow you to find any angle of a right triangle, given this information. The static methods Math.Atan, Math.Acos, and Math.Asin on the Math class provide the functionality to implement these trigonometric operations.
See Recipe 1.14; see the "Math Class" topic in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Displaying an Enumeration Value as a String
You need to display the textual or numeric value of an enumeration member.
To display an enumeration value as a string, use the ToString method that each enumeration member inherits from System.Enum.
Using the following ValidShape enumeration type as an example, you can obtain the textual and numeric values so that you can display them:
	enum ValidShape
	{
	    Square, Circle, Cylinder, Octagon
	}
Using the ToString method of the ValidShape enumeration type, you can derive the value of a specific ValidShape enumeration value directly:
	Console.WriteLine(ValidShape.Circle.ToString());
	Console.WriteLine(ValidShape.Circle.ToString("G"));
	Console.WriteLine(ValidShape.Circle.ToString("D"));
	Console.WriteLine(ValidShape.Circle.ToString("F"));
	Console.WriteLine(ValidShape.Circle.ToString("X"));
This generates the following output:
	Circle
	Circle
	1
	Circle
	00000001
If you are working with a variable of type ValidShape, the enumeration values can be derived in the same manner:
	ValidShape shapeStyle = ValidShape.Cylinder;

	Console.WriteLine(shapeStyle.ToString());
	Console.WriteLine(shapeStyle.ToString("G"));
	Console.WriteLine(shapeStyle.ToString("D"));
	Console.WriteLine(shapeStyle.ToString("F"));
	Console.WriteLine(shapeStyle.ToString("X"));
The following is displayed.
	Cylinder
	Cylinder
	2
	Cylinder
	00000002
Deriving the textual or numeric representation of an enumeration value is a simple matter, using the ToString instance method on the Enum type. This method can accept a character indicating the type of formatting to place on the enumeration value. The character can be one of the following: G, g, D, d, X, x, F, or f. See Table 1-2 for a description of these formatting types.
Table 1-2: Formatting types
Formatting type
Name
Description
G or g
(General)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Plain Text to an Equivalent Enumeration Value
You have the textual value of an enumeration element, possibly from a database or text file. This textual value needs to be converted to a usable enumeration type.
The static Parse method on the Enum class allows the textual value of an enumeration element to be converted to a usable enumeration value. For example:
	try
	{
	    Language proj1Language = (Language)Enum.Parse(typeof(Language),
	                            "VBNET");
	    Language proj2Language = (Language)Enum.Parse(typeof(Language),
	                            "UnDefined");
	}
	catch (ArgumentException e)
	{
	    // Handle an invalid text value here
	    //(such as the "UnDefined" string)
	}
where the Language enumeration is defined as:
	enum Language
	{
	    Other = 0, CSharp = 1, VBNET = 2, VB6 = 3
	}
The static Enum.Parse method converts text to a specific enumeration value. This technique is useful when a user is presented a list of values, with each value defined in an enumeration. When the user selects an item from this list, the text chosen can be easily converted from its string representation to its equivalent enumeration value using Enum.Parse. This method returns an object, which must then be cast to the target enum type in order to use it.
In addition to passing Enum.Parse a single enumeration value as a string, you can also pass the enumeration value as its corresponding numeric value. For example, consider the following line:
	Language proj1Language = (Language)Enum.Parse(typeof(Language),
	                                    "VBNET");
You can rewrite this as follows to perform the exact same action:
	Language proj1Language = (Language)Enum.Parse(typeof(Language), "2");
This is assuming that the Language.VBNET enumeration value is equal to 2.
Another interesting feature of the Parse method is that it can accept a comma-delimited list of enumeration names or values and then logically OR them together. The following example creates an enumeration with the languages VBNET and CSharp ORed together:
	Language proj1Language = (Language)Enum.Parse(typeof(Language),
	                        "CSharp, VBNET");
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing for a Valid Enumeration Value
When you pass a numeric value to a method that accepts an enumeration type, it is possible to pass a value that does not exist in the enumeration. You want to perform a test before using this numeric value to determine if it is indeed one of the ones defined in this enumeration type.
To prevent this problem, test for the specific enumeration values that you allow for the enumeration-type parameter using a switch statement to list the values.
Using the following Language enumeration:
	enum Language
	{
	    Other = 0, CSharp = 1, VBNET = 2, VB6 = 3
	}
Suppose you have a method that accepts the Language enumeration, such as the following method:
	public void HandleEnum(Language language)
	{
	    // Use language here…
	}
You need a method to define the enumeration values you can accept in HandleEnum. The CheckLanguageEnumValue method shown here does that:
	public static bool CheckLanguageEnumValue(Language language)
	{
	    switch (language)
	    {
	        // All valid typesfor the enum listed here
	        // This means only the ones we specify are valid.
	        // Not any enum value for this enum
	        case Language.CSharp:
	        case Language.Other:
	        case Language.VB6:
	        case Language.VBNET:
	             break;
	        default:
	        Debug.Assert(false, language +
	            " is not a valid enumeration value to pass.");
	        return false;
	    }
	    return true;
	}
Although the Enum class contains the static IsDefined method, it should not be used. IsDefined uses reflection internally, which incurs a performance penalty. Also, versioning of the enumeration is not handled well. Consider the scenario in which you add the value MgdCpp (managed C++) to the Languages enum in the next version of your software. If IsDefined is used to check the argument here, it will allow MgdCpp as a valid value, since it is defined in the enumeration, even though the code for which you are validating the parameter is not designed to handle it. By being specific with the switch statement shown in CheckLanguageEnumValue, you reject the MgdCpp
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing for a Valid Enumeration of Flags
You need to determine if a given value is a valid enumeration value or a valid combination of enumeration values (i.e., bit flags ORed together in an enumeration marked with the Flags attribute).
To make it possible to test whether a value is a valid enumeration value or some combination of valid enumeration values, add an All member to the existing enumeration equal to all the members of the enumeration ORed together. Then use the HandleFlagsEnum method to do the test.
There is a problem with using Enum.IsDefined with an enumeration marked with the Flags attribute. Consider if the Language enumeration was written as follows:
	[Flags]
	enum Language 
	{ 
	    CSharp = 1, VBNET = 2, VB6 = 4
	}
Valid values for Language are the set of numbers {1, 2, 3, 4, 5, 6, 7}. However, the values 3, 5, 6, and 7 are not explicitly represented in this enumeration. The value 3 is equal to the CSharp and VBNET enumeration members ORed together, and the value 7 is equal to all of the enumeration members ORed together. For the values 3, 5, 6, and 7, the Enum.IsDefined method will return false, indicating that these are not valid values, when in fact they are. You need a way to determine if a correct set of flags has been passed into a method.
To fix this problem you can add a new member to the Language enumeration to define all values for which the Language enumeration is valid. In this case, the Language enumeration would be rewritten as:
	[Flags]
	enum Language
	{
	    CSharp = 1, VBNET = 2, VB6 = 4,
	    All = (CSharp | VBNET | VB6)
	}
The new All enumeration member is equal to all other Language members ORed together. Now, when you want to validate a Language flag, all you have to do is the following:
	public bool HandleFlagsEnum(Language language)
	{
	    if ((language != 0) && ((language & Language.All) == language))
	    {
	        return (true);
	    }
	    else
	    {
	        return (false);
	    }
	}
If you want to use the HandleFlagsEnum method with existing code, all that is required is to add an All member to the existing enumeration. The All member should be equal to all the members of the enumeration ORed together.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Enumerated Members in a Bit Mask
An enumeration of values is needed to act as bit flags that can be ORed together to create a combination of values (flags) in the enumeration.
Mark the enumeration with the Flags attribute:
	[Flags]
	enum Language
	{
	    CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008
	}
Combining elements of this enumeration is a simple matter of using the bitwise OR operator (|). For example:
	Language lang = Language.CSharp | Language.VBNET;
Adding the Flags attribute to an enumeration marks this enumeration as individual bit flags that can be ORed together. Using an enumeration of flags is no different than using a regular enumeration type. It should be noted that failing to mark an enumeration with the Flags attribute will not generate an exception or a compiletime error, even if the enumeration values are used as bit flags.
The addition of the Flags attribute provides you with two benefits. First, if the Flags attribute is placed on an enumeration, the ToString and ToString("G") methods return a string consisting of the name of the constant(s) separated by commas. Otherwise, these two methods return the numeric representation of the enumeration value. Note that the ToString("F") method returns a string consisting of the name of the constant(s) separated by commas, regardless of whether this enumeration is marked with the Flags attribute. For an indication of why this works in this manner, see the "F" formatting type in Table 1-2 in Recipe 1.16.
The second benefit is that when you examine the code and encounter an enumeration, you can better determine the developer's intention for this enumeration. If the developer explicitly defined this as containing bit flags (with the Flags attribute), you can use it as such.
An enumeration tagged with the Flags attribute can be viewed as a single value or as one or more values combined into a single enumeration value. If you need to accept multiple languages at a single time, you can write the following code:
	Language lang = Language.CSharp | Language.VBNET;
The variable lang is now equal to the bit values of the two enumeration values ORed together. These values ORed together will equal 3, as shown here:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining if One or More Enumeration Flags Are Set
You need to determine if a variable of an enumeration type, consisting of bit flags, contains one or more specific flags. For example, given the following enumeration Language:
	[Flags]
	enum Language
	{
	    CSharp = 0x0001, VBNET = 0x0002, VB6 = 0x0004, Cpp = 0x0008
	}
determine, using Boolean logic, if the variable lang in the following line of code contains a language such as Language.CSharp and/or Language.Cpp:
	Language lang = Language.CSharp | Language.VBNET;
To determine if a variable contains a single bit flag that is set, use the following conditional:
	if((lang & Language.CSharp) == Language.CSharp)
	{
	    // Lang contains at least Language.CSharp.
	}
To determine if a variable exclusively contains a single bit flag that is set, use the following conditional:
	if(lang == Language.CSharp)
	{
	    // lang contains only the Language.CSharp.
	}
To determine if a variable contains a set of bit flags that are all set, use the following conditional:
	if((lang & (Language.CSharp | Language.VBNET)) ==
	  (Language.CSharp | Language.VBNET))
	{
	    // lang contains at least Language.CSharp and Language.VBNET.
	}
To determine if a variable exclusively contains a set of bit flags that are all set, use the following conditional:
	if((lang | (Language.CSharp | Language.VBNET)) ==
	  (Language.CSharp | Language.VBNET))
	{
	    // lang contains only the Language.CSharp and Language.VBNET.
	}
When enumerations are used as bit flags and are marked with the Flags attribute, they usually will require some kind of conditional testing to be performed. This testing necessitates the use of the bitwise AND (&) and OR (|) operators.
Testing for a variable having a specific bit flag set is done with the following conditional statement:
	if((lang & Language.CSharp) == Language.CSharp)
where lang is of the Language enumeration type.
The & operator is used with a bit mask to determine if a bit is set to 1. The result of ANDing two bits is 1 only when both bits are 1; otherwise, the result is 0. You can use this operation to determine if a specific bit flag is set to a 1 in the number containing the individual bit flags. If you AND the variable
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining the Integral Part of a Decimal or Double
You need to find the integer portion of a decimal or double number.
You can find the integer portion of a decimal or double by truncating it to the whole number closest to zero. To do so, use the overloaded static System.Math.Truncate method, which takes either a decimal or a double as an argument and returns the same type:
	decimal pi = (decimal)System.Math.PI;
	decimal decRet = System.Math.Truncate(pi); // decRet = 3

	double trouble = 5.555;
	double dblRet = System.Math.Truncate(trouble);
The Truncate method is new in the 2.0 version of the Framework and helps to "round" out the mathematical capabilities of the Framework. The Truncate method has the net effect of simply dropping the fractional portion of the number and returning the integral part. Once floating-point numbers get over a certain size, they do not actually have a fractional part, but have only an approximate representation of their integer portion.
See Recipe 1.9; see the "System.Math.Truncate Method" topic in the MSDN documentation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Strings and Characters
String usage abounds in just about all types of applications. The System.String type does not derive from System.ValueType and is therefore considered a reference type. The string alias is built into C# and can be used instead of the full name.
The FCL does not stop with just the String class; there is also a System.Text.StringBuilder class for performing string manipulations and the System.Text.RegularExpressions namespace for searching strings. This chapter will cover the String class and the System.Text.StringBuilder class.
The System.Text.StringBuilder class provides an easy, performance-friendly method of manipulating string objects. Even though this class duplicates much of the functionality of a String class, the StringBuilder class is fundamentally different in that the string contained within the StringBuilder object can actually be modified—you cannot modify a string object. However, this duplicated functionality provides a more efficient manipulation of strings than is obtainable by using the String class.
You have a variable of type char and wish to determine the kind of character it contains—a letter, digit, number, punctuation character, control character, separator character, symbol, whitespace, or surrogate character. Similarly, you have a string variable and want to determine the kind of character in one or more positions within this string.
To determine the value of a char, use the built-in static methods on the System.Char structure shown here:
	Char.IsControl            Char.IsDigit
	Char.IsLetter             Char.IsNumber
	Char.IsPunctuation        Char.IsSeparator
	Char.IsSurrogate          Char.IsSymbol
	Char.IsWhitespace
The following examples demonstrate how to use the methods shown in the Solution section in a function to return the kind of a character. First, create an enumeration to define the various types of characters:
	public enumCharKind
	{
	    Letter,
	    Number,
	    Punctuation,
	    Unknown
	}
Next, create a method that contains the logic to determine the type of a character and to return a CharKind
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction
String usage abounds in just about all types of applications. The System.String type does not derive from System.ValueType and is therefore considered a reference type. The string alias is built into C# and can be used instead of the full name.
The FCL does not stop with just the String class; there is also a System.Text.StringBuilder class for performing string manipulations and the System.Text.RegularExpressions namespace for searching strings. This chapter will cover the String class and the System.Text.StringBuilder class.
The System.Text.StringBuilder class provides an easy, performance-friendly method of manipulating string objects. Even though this class duplicates much of the functionality of a String class, the StringBuilder class is fundamentally different in that the string contained within the StringBuilder object can actually be modified—you cannot modify a string object. However, this duplicated functionality provides a more efficient manipulation of strings than is obtainable by using the String class.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining the Kind of Character a char Contains
You have a variable of type char and wish to determine the kind of character it contains—a letter, digit, number, punctuation character, control character, separator character, symbol, whitespace, or surrogate character. Similarly, you have a string variable and want to determine the kind of character in one or more positions within this string.
To determine the value of a char, use the built-in static methods on the System.Char structure shown here:
	Char.IsControl            Char.IsDigit
	Char.IsLetter             Char.IsNumber
	Char.IsPunctuation        Char.IsSeparator
	Char.IsSurrogate          Char.IsSymbol
	Char.IsWhitespace
The following examples demonstrate how to use the methods shown in the Solution section in a function to return the kind of a character. First, create an enumeration to define the various types of characters:
	public enumCharKind
	{
	    Letter,
	    Number,
	    Punctuation,
	    Unknown
	}
Next, create a method that contains the logic to determine the type of a character and to return a CharKind enumeration value indicating that type:
	public static CharKindGetCharKind(char theChar)
	{
	    if (Char.IsLetter(theChar))
	    {
	        return CharKind.Letter;
	    }
	    else if (Char.IsNumber(theChar))
	    {
	        return CharKind.Number;
	    }
	    else if (Char.IsPunctuation(theChar))
	    {
	        return CharKind.Punctuation;
	    }
	    else
	    {
	        return CharKind.Unknown;
	    }
	}
If, however, a character in a string needs to be evaluated, use the overloaded static methods on the char structure. The following code modifies the GetCharKind method to accept a string variable and a character position in that string. The character position determines which character in the string is evaluated.
	public static CharKind GetCharKindInString(string theString, int charPosition)
	{
	    if (Char.IsLetter(theString, charPosition))
	    {
	        return CharKind.Letter;
	    }
	    else if (Char.IsNumber(theString, charPosition))
	    {
	        return CharKind.Number;
	    }
	    else if (Char.IsPunctuation(theString, charPosition))
	    {
	        return CharKind.Punctuation;
	    }
	    else
	    {
	        return CharKind.Unknown;
	    }
	}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Determining Whether a Character Is Within a Specified Range
You need to determine whether a character in a char data type is within a range, such as between the numbers 1 and 5 or between the letters A and M.
Use the built-in comparison support for the char data type. The following code shows how to use the built-in comparison support:
	public static boolIsInRange(char testChar, char startOfRange, char endOfRange)
	{
	    if (testChar >= startOfRange && testChar <= endOfRange)
	    {
	        // testChar is within the range.
	        return (true);
	    }
	    else
	    {
	        // testChar is NOT within the range.
	        return (false);
	    }
	}
There is only one problem with that code. If the