Bogotobogo
contact@bogotobogo.com
Bookmark and Share




System Members and Data

csharp_logo



System Members and Data

System.Environment Class

The Environment class allows us to obtain a number of details related to the operating system via various static members.


Your Ad Here

Here is our new code:

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine("System.Environment Class");
            Console.WriteLine();
            ShowEnvDetails();
            Console.ReadLine();
            return -1;
        }

        static void ShowEnvDetails()
        {
            foreach (string drv in Environment.GetLogicalDrives())
                Console.WriteLine("Drive: {0}", drv);
            Console.WriteLine("OS: {0}", Environment.OSVersion);
            Console.WriteLine("# of processors: {0}",
                    Environment.ProcessorCount);
            Console.WriteLine(".NET Version: {0}", Environment.Version);
        }
    }
}


The output is:

System.Environment Class

Drive: C:\
Drive: D:\
Drive: E:\
Drive: F:\
Drive: Y:\
Drive: Z:\
OS: Microsoft Windows NT 6.0.6001 Service Pack 1
# of processors: 2
.NET Version: 4.0.30319.1


System Data Types

C# defines an intrinsic set of data types, which are used to represent local variables, member variables, return values, and input parameters. However, unlike other programming languages, these keywords are much more than simple compiler-recognized tokens. Rather, the C# data type keywords are actually shorthand notations for full-blown types in the System namespace. Following table lists each system data type, its range and the corresponding C# keyword.

C# Shorthand System Type Usage Range
bool System.Boolean boolean true, false
byte System.Byte 8 bit integer 0 - 255
char System.Char 16 bit Unicode character /u0000 - /uffff
decimal System.Decimal 128 bit decimal +/-1.0x10-28 to +/-7.9x10+28 precision of 28-29 digits
double System.Double 64 bit floating point -1.79769313486232e308 to 1.79769313486232e308
float System.Single 32 bit floating point +/-1.5x10-45 to +/-3.4x10+38 precision of 7 digits
int System.Int32 32 bit integer -2,147,483,648 to 2,147,483,647
long System.Int64 64 bit integer -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
sbyte System.SByte 8 bit integer -128 to 127
short System.Int16 16 bit integer -32,768 to 32,767
string System.String - immutable, specified length
object System.Object The base class of all types Can store any type in an object variable
uint System.UInt32 32 bit unsigned integer 0 to 4,294,967,295
ulong System.UInt64 64 bit unsigned integer 0 to 18,446,744,073,709,551,615
ushort System.UInt16 16 bit unsigned integer 0 to 65,535



table_assist

Each of the numerical types (short, int, etc.) map to a corresponding structure in the System namespace. The structures are value types allocated on the stack. On the other hand, string, and object are reference types, meaning the variable is allocated on the managed heap. Value types can be allocated into memory very quickly and have a very fixed and predictable lifetime.

Since the C# bool keyword is simply a shorthand notation for the System.Boolean structure, it is possible to allocate any data type using its full name as shown below:

bool b1 = true;
System.Boolean b2 = false;


Intrinsic Data Types with new

All intrinsic data types support default constructor. This allows us to create a variable using the new keyword, which automatically sets the variable to its default value:

  • bool types are set to false.
  • Numeric data is set to 0 or 0.0 in the case of floating-point data types.
  • char types are set to a single empty character.
  • DataTime types are set to 1/1/1001 12:00:00 AM.
  • Object references including strings are set to null.

The following is an example:

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Using_new();
            Console.ReadLine();
            return -1;
        }

        static void Using_new()
        {
            Console.WriteLine("Using new:"); 
            bool b=new bool();
            int i = new int();
            double d = new double();
            DateTime dt=new DateTime();
            Console.WriteLine("{0}, {1}, {2}, {3}", b, i, d, dt);
            Console.WriteLine();
        }
    }
}

With an output:

Using new:
False, 0, 0, 1/1/0001 12:00:00 AM


Hierarchy of System Types

The primitive .NET data types are arranged in a class hierarchy. Types at the top of a class hierarchy provide default behaviors that are granted to the derived types.

hierarchy_system_type

Each of these types derives from System.Object, which defines a set of methods such as ToString(), Equals(), GatHashCode(), etc. They are common to all types in the .NET base class libraries.

Many numerical data types derive from System.ValueType. Descendents of ValueType are automatically allocated on the stack and therefore have a very predictable lifetime and are quite efficient. On the other hand, types that do not have System.ValueType in their inheritance hierarchy (such as System.Type, System.String, System.Array, System.Exception, and System.Delegate are not allocated on the stack but on the garbage-collected heap.

The following code is perfectly legal syntax, given that System.Int32 (the C# int) eventually derives from System.Object and therefore can invoke any of its public members as shown below.

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_Object_Functionality();
            Console.ReadLine();
            return -1;
        }

        static void Show_Object_Functionality()
        {
            Console.WriteLine("System Object Functionality:"); 
            Console.WriteLine("2010.GetHashCode() = {0}", 2010.GetHashCode());
            Console.WriteLine("2010.Equals(2011) = {0}", 2010.Equals(2011));
            Console.WriteLine("2010.ToString() = {0}", 2010.ToString());
            Console.WriteLine("2010.GetType() = {0}", 2010.GetType());
            Console.WriteLine();
        }
    }
}

The output is:

System Object Functionality:
2010.GetHashCode() = 2010
2010.Equals(2011) = False
2010.ToString() = 2010
2010.GetType() = System.Int32


Numerical and Boolean Data Types

Numerical types of .NET support MaxValue and MinValue properties that provide information regarding the range a given type can store. Here is an example showing additional members.

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_Data_Functionality();
            Console.ReadLine();
            return -1;
        }

        static void Show_Data_Functionality()
        {
            Console.WriteLine("Data Type Functionality:"); 
            Console.WriteLine("Max of int: {0}", int.MaxValue);
            Console.WriteLine("Min of int: {0}", int.MinValue);
            Console.WriteLine("Max of double: {0}", double.MaxValue);
            Console.WriteLine("Min of double: {0}", double.MinValue);
            Console.WriteLine("double.Epsilon: {0}", double.Epsilon);
            Console.WriteLine("double.PositiveInfinity: {0}", double.PositiveInfinity);
            Console.WriteLine("double.NegativeInfinity: {0}", double.NegativeInfinity);
            Console.WriteLine("bool.FalseString: {0}", bool.FalseString);
            Console.WriteLine("bool.TrueString: {0}", bool.TrueString);

            Console.WriteLine();
        }
    }
}

The output is:

Data Type Functionality:
Max of int: 2147483647
Min of int: -2147483648
Max of double: 1.79769313486232E+308
Min of double: -1.79769313486232E+308
double.Epsilon: 4.94065645841247E-324
double.PositiveInfinity: Infinity
double.NegativeInfinity: -Infinity
bool.FalseString: False
bool.TrueString: True


System Character and String Data Types

C#'s string and char keywords are simple shorthand notations for System.String and System.char both of which are Unicode. Here is an example code:

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_Data_Functionality();
            Console.ReadLine();
            return -1;
        }

        static void Show_Data_Functionality()
        {
            Console.WriteLine("Character and String Type Functionality:");
            char myChar = 'a';
            Console.WriteLine("char.IsDigit('a'): {0}", 
				char.IsDigit(myChar));
            Console.WriteLine("char.IsLetter('a'): {0}", 
				char.IsDigit('a'));
            Console.WriteLine("char.IsWhiteSpace('Hello World!', 5): {0}",
				char.IsWhiteSpace("Hello World!", 5));
            Console.WriteLine("char.IsWhiteSpace('Hello World!', 7): {0}", 
				char.IsWhiteSpace("Hello World!", 7));
            Console.WriteLine("char.IsPunctuation('!'): {0}",
				 char.IsPunctuation('!'));
            Console.WriteLine();

            bool b = bool.Parse("True");
            Console.WriteLine("Value of b: {0}", b);
            double d = double.Parse("3.14");
            Console.WriteLine("Value of d: {0}", d);
            int i = int.Parse("2010");
            Console.WriteLine("Value of i: {0}", i);
            char c = Char.Parse("w");
            Console.WriteLine("Value of c: {0}", c);
            Console.WriteLine();
        }
    }
}

Output of the code:

Character and String Type Functionality:
char.IsDigit('a'): False
char.IsLetter('a'): False
char.IsWhiteSpace('Hello World!', 5): True
char.IsWhiteSpace('Hello World!', 7): False
char.IsPunctuation('!'): True

Value of b: True
Value of d: 3.14
Value of i: 2010
Value of c: w


Verbatim Strings

When we prefix a string literal with the @ symbol, we have created a verbatim string. Using verbatim strings, we disable the processing of a literal's escape characters and print out a string as is.

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_Verbatim_Functionality();
            Console.ReadLine();
            return -1;
        }

        static void Show_Verbatim_Functionality()
        {
            Console.WriteLine("Verbatim Functionality:");
            Console.WriteLine(@"C:\MyDrectory\myCSharp.cs");
            Console.WriteLine(
                @"This is multiline strings 
                string 1
                string 2");
            Console.WriteLine(@"John McAfe said in1988,
                ""The problem of viruses is temporary
                and will be solved in two years"" ");
        }
    }
}

Output is:

Verbatim Functionality:
C:\MyDrectory\myCSharp.cs
This is multiline strings
                string 1
                string 2
John McAfe said in1988,
                "The problem of viruses is temporary
                and will be solved in two years"


Strings Are Immutable

Once we assign a string object with its initial value, the character data cannot be changed. Sting type defines a number of methods that appear to modify the character data in one way or the other such as uppercasing, lowercasing, and so on. But, if we look more closely at what is happening behind the scenes, we'll notice the methods of the string type are actually returning us a brand-new string object in a modified format.

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_Strings_are_Immutable();
            Console.ReadLine();
            return -1;
        }

        static void Show_Strings_are_Immutable()
        {
            string s1 = "Once you're over the hill you begin to pick up speed.";
            Console.WriteLine("s1 = {0}", s1);

            string uString = s1.ToUpper();
            Console.WriteLine("uString = {0}", uString);

            Console.WriteLine("s1 = {0}", s1);
        }
    }
}

With an output:

s1 = Once you're over the hill you begin to pick up speed.
uString = ONCE YOU'RE OVER THE HILL YOU BEGIN TO PICK UP SPEED.
s1 = Once you're over the hill you begin to pick up speed.

The original string object, s1 is not uppercased when calling ToUpper(). Rather we are returned a copy of the string in a modified format.

The same law of immutability holds true when we use the C# assignment operator. To demonstrate, comment out any existing code of the previous example, and add the following code:

static void Show_Strings_are_Immutable()
{
	string s1 = "Once you're over the hill you begin to pick up speed.";
	s1 = "New string value";
}

Load the assembly into ildasm.exe after the compile.


ildasm

Then, double-click Show_Strings_are_Immutable() method, we get CIL code as shown in the picture below.


cil

Although we have yet to examine the low-level details of the Common Intermediate Language (CIL), note that the Show_Strings_are_Immutable() method makes numerous calls to the ldstr (load string) opcode. The ldstr opcode of CIL loads a new string object on the managed heap. The previous string object that contained the value Once you're over the hill you begin to pick up speed. will eventually be garbage collected.

The string type can be inefficient and result in bloated code if misused, especially performing string concatenation. If we need to represent basic character data such as first or last name, the string data type is the perfect choice.

But if we are building an application that makes heavy use of texture data such as a word processing program, it would be a bad idea to represent the word processing data using string types. Because we will most certainly end up making unnecessary copies of string data.



System.Text.StringBuilder

StringBuilder defines methods that allow us to replace or format segments. To use this type, we need to import the proper namespace:

using System.Text;

When we call members of StringBuilder, we are directly modifying the object's internal character data instead of obtaining a copy of the data in a modified format. When we create an instance of the StringBuilder, we can supply the object's initial startup values via one of many constructors. Let's look at the code which shows the usage of StringBuilder.

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyFirstCSharpCode
{
    class Program
    {
        static int Main(string[] args)
        {
            Console.WriteLine();
            Show_StringBuilder_Functionality();
            Console.ReadLine();
            return -1;
        }

        static void Show_StringBuilder_Functionality()
        {
            StringBuilder sb = new StringBuilder("Simplicity, "); 
            sb.AppendLine("carried to the extreme, ");
            sb.AppendLine("becomes elegance!");
            sb.Append("\n");
            sb.AppendLine("Jon Franklin");
            Console.WriteLine(sb.ToString());

            sb.Replace("!", ".");
            Console.WriteLine(sb.ToString());
            Console.WriteLine("sb has {0} chars.", sb.Length);
            Console.WriteLine();
        }
    }
}

Output is:

Simplicity, carried to the extreme,
becomes elegance!

Jon Franklin

Simplicity, carried to the extreme,
becomes elegance.

Jon Franklin

sb has 72 chars.

As we see, we are appending to the internal buffer, and are able to replace (or remove) characters. By default, a StringBuilder is only able to hold a string of 16 characters or less. But this initial value can be changed via an additional constructor argument.





List of C# 4.0 Tutorials
  • Networking II - WebRequest/WebResponse, WebClient