Technology Writing

Creating C# Applications: Chapter 4

One of the most innovative features of C# is the concept of managed and unmanaged code. It is this that truly differentiates this language from its more commonly used cousins, C++ and Java.

What is unmanaged code? Well, put simply, unmanaged code is any C# code that uses pointers. Conversely, managed code could be considered to be any use of C# that doesn’t include the use of pointers. However, the concept goes beyond these simple statements.

In C++ if you want to work with a block of data, such as a large text string (anything that isn’t a simple scalar value), you must allocate the resources for the string, initialize and use the resource, and then free or deallocate it manually when you’re finished. To pass a reference to the string in a function you wouldn’t need to pass the entire string, but only a pointer to the string’s location in memory, its address. Using pointers is efficient, but one of the problems with manual allocation of resources and the use of pointers is that the developer may forget to free the resource, causing a loss of the resource commonly referred to as a memory leak. After many iterations of the code, the application’s performance can degrade, and may even stop performing.

Java eliminated this problem by eliminating the need to manually allocate and deallocate resources. The Java Virtual Machine (VM) provides the resources necessary to support the application and also provides garbage collection (defined in more detail in the next section) to clean up and free the resources after the application is finished. This approach prevents problems of lost resources but also prevents the use of pointers as the support for garbage collection and pointers are mutually exclusive.

C# eliminates the problem of having to choose between the use of pointers and the associated problems of resource loss, and automatic garbage collection but without support for pointers. The language does this by providing support for both garbage collection and pointers — if you follow rules carefully defined within the language that allows both of these seemingly incompatible capabilities.

In addition to the support for managed and unmanaged code, C# also has other unique concepts available to it based on the runtime language support provided by the Common Language Runtime (CLR), such as the WeakReference wrapper class, useful with larger objects and collections.

First, though, let’s take a closer look in the next section at why the use of pointers and garbage collection are so contradictory. If you already know this, you can skip to the section titled “Managed and Unmanaged code,” following.

Garbage Collection and Pointers

As stated earlier, in a programming language that doesn’t provide automatic management of resources, you must allocate and initialize the resource and then deallocate it when finished. However, when garbage collection is supported, you don’t have to manage the resources as the garbage collection mechanism does this for you.

Within the CLR environment, storage space for a new object is pulled from a managed heap. As a new object is created, it’s allocated space within the heap and an address is assigned to the object that references the starting address of its location in the heap. The object’s given the next available space within the heap that can contain it completely.

The amount of space in the heap assigned to the object depends on the structure of the object. A pointer is used to traverse the heap until a contiguous block of space large enough to fit the object is found.

Garbage collection is used to find objects that are no longer being used and to free up the heap space the object is occupying. In the Common Language Infrastructure (CLI) architecture, the garbage collection mechanism is triggered when the pointer used to search for an available heap location travels past the boundaries of the heap.

During the garbage collection process, the collection mechanism visits each address on the heap, checks to see if the object is still being referenced (can be reached and is therefore accessible by existing process) and then freeing up the space if the object is no longer within the scope of the existing process or application scope. The mechanism also optimizes the heap by shifting the addresses (the pointers) of existing objects to provide contiguous blocks of free space for new objects as they are allocated.

This last statement actually explains why manual creation of pointers and garbage collection are not compatible within the same development environment. You can’t create an object and reference it via a pointer to an address that could then be modified by an automatic garbage collection mechanism, thereby making your reference — the pointer — meaningless.

In addition, in this process the garbage collection mechanism must know how much space an object takes up — its structure — in order to manage it efficiently. In C++, it isn’t unusual to cast a pointer from one object/structure type to another, making garbage collection virtually impossible as the mechanism wouldn’t be able to determine the exact structure of the object, and therefore how much space is needed or occupied.

The problem of using pointers and garbage collection in one language is solved through the use of managed and unmanaged code, discussed next.

Technology Writing

Creating C# Applications: Chapter 3

When I work with more than one programming language at a time, such as Java and Perl or VB and C#, the biggest problem I have keeping the languages untangled is remembering to use a semi-colon (;) or not when ending the statement. No matter how hard I try to keep my language syntax separate, I always include the semi-colon when I shouldn’t (such as in VB), or not include it when I should (such as in C++ or Java or C#).

Regardless of the sophistication of a programming language, you must first become proficient with the operators and special characters supported in the language before advancing on its more escoteric elements, and this chapter provides coverage of C#’s operators and special character set — including the infamous semi-colon.

Arithmetic and Concatenation Characters

The simplest of the operators for C# are the arithmetic operators. The addition operator (‘+’) is used to add two numbers together, as it’s used in most other programming languages, such as C++. In addition, the + operator is an example of an overloaded operator within C#. What this means is that you can use it for adding numbers and you can also use it to add two strings together (concatenation), or add a string and a number. An overloaded operator is one that can work with different parameters, or parameter types. C# extends this capability by also translating parameters to compatible types — such as converting an integer to a string for concatenation when adding a string and an integer.

To demonstrate this capability, in the following code, the addition operator is used to add two numbers and two strings and print out the results of both operations.

using System;

class ArithTest 
   public static void Main() 
        int i = 6;
	     string s1 = "Value";
        string s2 = " is ";

        // add two numbers
        i = i + 4;
        // add two strings
        s1 = s1 + s2;

        // add a string and a number
	     s2 = s1 + i;

        // output values

The result from running this application is:

Value is
Value is 10

The plus sign can’t convert automatically between the two operands if the result is ambiguous, or disallowed for implicit type conversion. If you try to add a double to an integer, as shown in the following line of code:

i = i + 4.15

An error results when you compile the application because you can’t implicitly convert a double to an integer.

The addition operator can also be used to perform delegate concatenation, covered in more detail in Chapter 10 “Delegates and Events”.

The addition operator is both a binary operator, meaning that there are two operands for an expression containing the operator, and a unary operator. A unary operator applies to only one operand. Applying the addition operator as a unary operator to an operand just returns the value of the operand:

nVal = i+;

The subtraction operator (‘-‘) is used to subtract one number from another, or to negate the value of an operand, as demonstrated in the following code:

using System;

class ArithTest 
   public static void Main() 
        int i = 6;

        // subtract smaller value
        Console.WriteLine(i - 2);

        // subtract larger value
        Console.WriteLine(i - 7);

        // unary

The following values are output when this application is run:


The subtraction operator, as with the other arithmetic operators, works with all numeric data types, such as integers, doubles, and decimals.

The multiplication operator (‘*’) multiplies two operands together, while the division operator (‘/’) divides the first number by the second. The modulus operator (‘%’) returns only the remainder after the first operand is divided by the second.

In the following code, each of the operators just described is used between two different operands, both of which are type double, and the results are printed out:

using System;

class ArithTest 
   public static void Main() 
        double d1 = 4.15;
        double d2 = 1.23;

        //  multiply
        Console.WriteLine(d1 * d2);

        // divide
        Console.WriteLine(d1 / d2);

        // modulus
        Console.WriteLine(d1 % d2);

The output of this application is:


The multiplication operator is another example of an overloaded operator; it’s also used when declaring pointers, and de-referencing these pointers to access the pointer values as you’ll see in the section “Membership, Array, and Casting Operators” later in this chapter.

With all arithmetic operations, if an overflow occurs because the result is too large for the allowed range of the data type, an OverflowException is thrown if one of the following conditions is met:

  • The checked compiler option is used and
  • The data types of the operands are integers (int, long, or ulong)
  • Or the operands are decimals

Use the checked compiler option when compiling the application in order to generate an OverflowException with integers. This compiler option turns on arithmetic checking:

csc /checked test.cs

In the following C# application, the OverflowException is captured and the error message printed out:

using System;

class ArithTest 
   public static void Main() 
        int i = 2147148000;
        int i2 = 32000;

           //  multiply
           i = i * i2;
        catch (OverflowException e)
           Console.WriteLine("{0}", e);

When the application is compiled without the checked option, the following output results:


Since integer arithmetic checking isn’t turned on, the significant high-order bits are discarded, and the resulting value is returned. When checking is turned on with the check compiler option, the following exception message is printed out:

System.OverflowException: An exception of type 
   System.OverflowException was thrown.
   at ArithTest.Main() 

The OverflowException will occur with all decimal values when the value is too large for the decimal format.

Float and double values don’t generate an overflow exception. Following the IEEE 754 arithmetic specification, values too large for the variable are set to infinity. If a value can’t be defined as a numeric, it is given the constant NaN — meaning Not a Number.

Arithmetic and concatenation operators are useful for converting values, but have no impact on an application’s process. In addition, each of the variables modified by the operators in this section first had to be assigned. Program flow controlled through the use of logical and condition operators and the assignment operators are discussed next.


Creating C# Applications: Chapter 2

If you had a chance to design a programming language from the ground up, what would you include? Would you include support for pointers as C++ does? Or would you support the concept of automatic garbage collection, forming the basis of memory management in Java.

Perhaps you’d support the loose typing implemented in Visual Basic 6.0. Or you could opt for strong type safety, instead. Would you require that the developers pass pointers to the objects; or would you support the concept of marking a parameter as passed by reference and hence modifiable within the function?

The creators of C# at Microsoft have had a chance to look at programming language use in the last several years and ask themselves these questions. The result is an intriguing language that takes bits and pieces of several different development languages and environments and rolls them all into one.

In addition to the design of C#, the language architects also took a look at programming language interoperability, including issues such as data typing across programming languages. As a result of this effort, the Microsoft language architects participated in the design of a programming language infrastructure that supports interoperability between different programming languages, an infrastructure called the Common Language Infrastructure (CLI).

Before getting into more detail on the CLI and its impact on the design of C#, let’s take a quick look at how C# compares with three more commonly used programming languages, C++, and Visual Basic, too.

C#: A little C++, some Java, and a Touch of VB

C# owes its roots to more than one programming language. Specifically, you can see elements of three different languages in its makeup: C++, Java, and Visual Basic (though VB is a development environment and a language). Or perhaps it would be better to say that you can see the roots of programming language design that went into the composition of C++, Java, and VB in addition to other programming languages.

For instance, memory management in Java is handled by automatic garbage collection. However, automatic memory management is also used with LISP and other languages, so the use of garbage collection in C# can be attributed to LISP as much as it can be attributed to Java.

C# supports the concept of passing parameters by reference with the Ref keyword, or passing output parameters using the Out keyword. This concept is similar to the support of input/output parameter with Visual Basic. However, you can see an exact same implementation in Inprise’s Delphi product, based on Pascal. This similarity isn’t too surprising considering that one of the creators of C# is Anders Hejlsberg, formerly of Inprise.

There are also aspects of C# that are unique to it when compared with the more commonly used C++ or Java. For instance, the aspect of C# that intrigues me the most is the language’s support for unmanaged as well as managed code through the use of the unsafe keyword. Though covered in detail in the later chapter, Chapter 17, “Outside the Bounds — Memory Management, Unmanaged Code, and the Use of Unsafe”, I did want to mention it briefly now.

Using unsafe and a companion keyword, fixed, you can mark specific code within a C# application as unmanaged code. Doing this prevents automatic memory collection from occurring in this section of code. The other part of the C# application that isn’t marked as unsafe, can still be managed with automatic garbage collection. This hybrid approach to memory management allows C# developers to use language constructs such as pointers, while still taking advantage of automatic garbage collection techniques to control memory usage.

So, we can view C# as the latest culmination of several years of programming language research — at least, until another language appears on the programming language horizon.