#993 – Some Examples of Characters

Given that the System.Char data type (char) can store any Unicode character, encoded using UTF-16, below are some examples of valid characters.

Here is the list that we bind to, to display some characters:

            CharList = new ObservableCollection<char>
            {
                'a', 'Z', '.', '$', '\x00e1', '\x00e7', '\x0398', '\x03a9',
                '\x0429', '\x046c', '\x05d4', '\x05da', '\x0626', '\x0643',
                '\x0b92', '\x0caf', '\x0e0d', '\x1251', '\x13ca', '\x14cf',
                '\x21bb', '\x21e9', '\x222d', '\x2285', '\x2466', '\x2528',
                '\x2592', '\x265a', '\x265e', '\x2738', '\x3062', '\x3063',
                '\x3082', '\x3071', '\x3462', '\x3463', '\x3464', '\x3485',
                '\x5442', '\x54e1', '\x5494', '\xac21', '\xae25', '\xfc45',
                '\xfce8'
            };

993-001

#992 – The System.Char Data Type

In C#, the char keyword is a synonym for the System.Char data type in the Base Class Library (BCL).  An instance of a char represents a single character, i.e. a single unit that is part of a written language.

Some examples of characters, all of which can be represented by a char:

  • Uppercase or lowercase alphabetic characters from the English (Latin) alphabet (a..z, A..Z)
  • Accented alphabetic characters
  • Alphabetic characters from other alphabets (e.g. Greek, Cyrillic, Hebrew, Chinese, Arabic, etc).
  • Punctuation marks  (e.g. ! , = [ {, etc).
  • Numeric digits (0..9)
  • Control or formatting characters (e.g. end-of-line, delete)
  • Mathematical and musical symbols
  • Special graphical glyphs (e.g. trademark symbol, smiley face)

A character stored in an instance of a char takes up 2 bytes (16 bits).  The values are encoded as Unicode characters, using the UTF-16 encoding.

#991 – Using the Round-Trip Format Specifier

Normally, when converting a floating point value to a string, you can lose some precision.  If you then later need to convert from the string back to the original floating point data type, you could end up with a different value.  In the example below, we convert from a double to a string and then back again.  But the double that we get in the end is not equal to the original value.

            double d1 = 0.123456789123456789;
            string s1 = d1.ToString();
            double d1b = double.Parse(s1);
            bool b1 = (d1 == d1b);

991-001
You can use the “R” format specifier when converting to a string to indicate that you want to be able to convert back to a floating point value without loss of precision.

            double d1 = 0.123456789123456789;
            string s1 = d1.ToString("R");
            double d1b = double.Parse(s1);
            bool b1 = (d1 == d1b);

991-002

#990 – Converting Hexadecimal Strings to Numeric Data

You can convert a numeric value to its equivalent hex string using the hexadecimal format specifier.  To convert in the other direction, from a hex string to its corresponding integer value, you use the int.Parse function, passing NumberStyles.AllowHexSpecifier as the second parameter.

            // using System.Globalization
            int n = int.Parse("A", NumberStyles.AllowHexSpecifier);
            int n2 = int.Parse("9D", NumberStyles.AllowHexSpecifier);
            int n3 = int.Parse("400", NumberStyles.AllowHexSpecifier);
            int n4 = int.Parse("1b3f", NumberStyles.AllowHexSpecifier);
            int n5 = int.Parse("000b", NumberStyles.AllowHexSpecifier);

990-001

#989 – Formatting Numbers as Hexadecimal

You can represent an integer as a series of hexadecimal characters by using the hexadecimal format specifier in a format string.

In the examples below, we represent several integers using their hexadecimal characters.  We use the X notation in the format string to indicate that the number should be displayed as hex.

            Console.WriteLine("{0} = {0:X}", 10);    // A
            Console.WriteLine("{0} = {0:X}", 157);   // 9D = (9 * 16) + 13
            Console.WriteLine("{0} = {0:X}", 1024);  // 400 = (4 * 256)
            Console.WriteLine("{0} = {0:X}", 6975);  // 1B3F = (1 * 4096) + (11 * 256) + (3 * 16) + 15

989-001
You can include a digit after the X to indicate the number of minimum digits to be displayed. The hex number will be padded with zeroes to reach the desired width.

            Console.WriteLine("{0} = {0:X4}", 157);   // 009D

989-002

#988 – Using global to Explicitly Refer to a Namespace

A fully qualified namespace is not always sufficient to refer to a type.  Below, we’ve (unwisely) declared two different classes named Utility–a subclass of Program in the ConsoleApplication1 namespace and a class in the Program namespace.

If we refer to Program.Utility from within the Main method, the subclass is used.  To use the other version of Utility, we need to use the global keyword to describe the exact path to the type.  global::Program refers to the top-level namespace Program.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Class Program.Utility in namespace ConsoleApplication1
            Program.Utility util = new Program.Utility();

            // Class Utility in namespace Program
            global::Program.Utility util2 = new global::Program.Utility();
        }

        class Utility
        {
            public Utility()
            {
                Trace.WriteLine("Class Program.Utility in namespace ConsoleApplication1");
            }
        }
    }

}

namespace Program
{
    public class Utility
    {
        public Utility()
        {
            Trace.WriteLine("Class Utility in namespace Program");
        }
    }
}

#987 – The using Directive Can Create an Alias for a Type

You can use the using directive to create an alias for a namespace, which you can then use to access the types in that namespace.  For example:

using U1 = DogLibrary.Utility.StandardLogging;
using U2 = DogLibrary.Utility.AlternateLogging;

We might do the above if we had an identically named type in each of the two namespaces so that we could then prefix the type with the appropriate namespace.

U1.DogLogger log1 = new U1.DogLogger(@"C:\log1.txt");
U2.DogLogger log2 = new U2.DogLogger(@"C:\log2.txt");

We can also use the using directive to create an alias for a specific type.  For the example above, we could do the following:

using Logger1 = DogLibrary.Utility.StandardLogging.DogLogger;
using Logger2 = DogLibrary.Utility.AlternateLogging.DogLogger;

We could then use the alias directly as a type name:

            // Short for DogLibrary.Utility.StandardLogging.DogLogger
            Logger1 log1 = new Logger1(@"C:\log1.txt");

            // Short for DogLibrary.Utility.AlternateLogging.DogLogger
            Logger2 log2 = new Logger2(@"C:\log2.txt");