1. Introduction
C# is a simple, modern, object oriented, and type-safe programming language derived from C and C++. C#
(pronounced “C sharp”) is firmly planted in the C and C++ family tree of languages, and will immediately be
familiar to C and C++ programmers. C# aims to combine the high productivity of Visual Basic and the raw
power of C++.
C# is provided as a part of Microsoft Visual Studio 7.0. In addition to C#, Visual Studio supports Visual Basic,
Visual C++, and the scripting languages VBScript and JScript. All of these languages provide access to the Next
Generation Windows Services (NWGS) platform, which includes a common execution engine and a rich class
library. The .NET software development kit defines a "Common Language Subset" (CLS), a sort of lingua
franca that ensures seamless interoperability between CLS-compliant languages and class libraries. For C#
developers, this means that even though C# is a new language, it has complete access to the same rich class
libraries that are used by seasoned tools such as Visual Basic and Visual C++. C# itself does not include a class
library.
The rest of this chapter describes the essential features of the language. While later chapters describe rules and
exceptions in a detail-oriented and sometimes mathematical manner, this chapter strives for clarity and brevity at
the expense of completeness. The intent is to provide the reader with an introduction to the language that will
facilitate the writing of early programs and the reading of later chapters.
1.1 Hello, world
The canonical “Hello, world” program can be written in C# as follows:
using System;
class Hello
{
static void Main() {
Console.WriteLine("Hello, world");
}
}
The default file extension for C# programs is .cs, as in hello.cs. Such a program can be compiled with the
command line directive
csc hello.cs
which produces an executable program named hello.exe. The output of the program is:
Hello, world
Close examination of this program is illuminating:
• The using System; directive references a namespace called System that is provided by the .NET
runtime. This namespace contains the Console class referred to in the Main method. Namespaces
provide a hierarchical means of organizing the elements of a class library. A “using” directive enables
unqualified use of the members of a namespace. The “Hello, world” program uses
Console.WriteLine as a shorthand for System.Console.WriteLine. What do these identifiers
denote? System is a namespace, Console is a class defined in that namespace, and WriteLine is a
static method defined on that class.
C# LANGUAGE REFERENCE
2 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
• The Main function is a static member of the class Hello. Functions and variables are not supported at
the global level; such elements are always contained within type declarations (e.g., class and struct
declarations).
• The “Hello, world” output is produced through the use of a class library. C# does not itself provide a
class library. Instead, C# uses a common class library that is also used by other languages such as Visual
Basic and Visual C++.
For C and C++ developers, it is interesting to note a few things that do not appear in the “Hello, world”
program.
• The program does not use either “::” or “->” operators. The “::” is not an operator in C# at all, and
the “->” operator is used in only a small fraction of C# programs. C# programs use “.” as a separator in
compound names such as Console.WriteLine.
• The program does not contain forward declarations. Forward declarations are never needed in C#
programs, as declaration order is not significant.
• The program does not use #include to import program text. Dependencies between programs are
handled symbolically rather than with program text. This system eliminates barriers between programs
written in different languages. For example, the Console class could be written in C# or in some other
language.
1.2 Automatic memory management
Manual memory management requires developers to manage the allocation and de-allocation of blocks of
memory. Manual memory management is both time consuming and difficult. C# provides automatic memory
management so that developers are freed from this burdensome task. In the vast majority of cases, this automatic
memory management increases code quality and enhances developer productivity without negatively impacting
either expressiveness or performance.
The example
using System;
public class Stack
{
private Node first = null;
public bool Empty {
get {
return (first == null);
}
}
public object Pop() {
if (first == null)
throw new Exception("Can't Pop from an empty Stack.");
else {
object temp = first.Value;
first = first.Next;
return temp;
}
}
public void Push(object o) {
first = new Node(o, first);
}
Chapter 1 Introduction
Copyright Microsoft Corporation 1999-2000. All Rights Reserved. 3
class Node
{
public Node Next;
public object Value;
public Node(object value): this(value, null) {}
public Node(object value, Node next) {
Next = next;
Value = value;
}
}
}
shows a Stack class implemented as a linked list of Node instances. Node instances are created in the Push
method and are garbage collected when no longer needed. A Node instance becomes eligible for garbage
collection when it is no longer possible for any code to access it. For instance, when an item is removed from
the Stack, the associated Node instance becomes eligible for garbage collection.
The example
class Test
{
static void Main() {
Stack s = new Stack();
for (int i = 0; i < 10; i++)
s.Push(i);
while (!s.Empty)
Console.WriteLine(s.Pop());
}
}
shows a test program that uses the Stack class. A Stack is created and initialized with 10 elements, and then
assigned the value null. Once the variable s is assigned null, the Stack and the associated 10 Node instances
become eligible for garbage collection. The garbage collector is permitted to clean up immediately, but is not
required to do so.
For developers who are generally content with automatic memory management but sometimes need fine-grained
control or that extra iota of performance, C# provides the ability to write “unsafe” code. Such code can deal
directly with pointer types, and fix objects to temporarily prevent the garbage collector from moving them. This
“unsafe” code feature is in fact “safe” feature from the perspective of both developers and users. Unsafe code
must be clearly marked in the code with the modifier unsafe, so developers can't possibly use unsafe features
accidentally, and the C# compiler and the execution engine work together to ensure that unsafe code cannot
masquerade as safe code.
The example
using System;
C# LANGUAGE REFERENCE
4 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
class Test
{
unsafe static void WriteLocations(byte[] arr) {
fixed (byte *p_arr = arr) {
byte *p_elem = p_arr;
for (int i = 0; i < arr.Length; i++) {
byte value = *p_elem;
string addr = int.Format((int) p_elem, "X");
Console.WriteLine("arr[{0}] at 0x{1} is {2}", i, addr, value);
p_elem++;
}
}
}
static void Main() {
byte[] arr = new byte[] {1, 2, 3, 4, 5};
WriteLocations(arr);
}
}
shows an unsafe method named WriteLocations that fixes an array instance and uses pointer manipulation to
iterate over the elements and write out the index, value, and location of each. One possible output of the
program is:
arr[0] at 0x8E0360 is 1
arr[1] at 0x8E0361 is 2
arr[2] at 0x8E0362 is 3
arr[3] at 0x8E0363 is 4
arr[4] at 0x8E0364 is 5
but of course the exact memory locations are subject to change.
see you soon in the second lecture.
C# is a simple, modern, object oriented, and type-safe programming language derived from C and C++. C#
(pronounced “C sharp”) is firmly planted in the C and C++ family tree of languages, and will immediately be
familiar to C and C++ programmers. C# aims to combine the high productivity of Visual Basic and the raw
power of C++.
C# is provided as a part of Microsoft Visual Studio 7.0. In addition to C#, Visual Studio supports Visual Basic,
Visual C++, and the scripting languages VBScript and JScript. All of these languages provide access to the Next
Generation Windows Services (NWGS) platform, which includes a common execution engine and a rich class
library. The .NET software development kit defines a "Common Language Subset" (CLS), a sort of lingua
franca that ensures seamless interoperability between CLS-compliant languages and class libraries. For C#
developers, this means that even though C# is a new language, it has complete access to the same rich class
libraries that are used by seasoned tools such as Visual Basic and Visual C++. C# itself does not include a class
library.
The rest of this chapter describes the essential features of the language. While later chapters describe rules and
exceptions in a detail-oriented and sometimes mathematical manner, this chapter strives for clarity and brevity at
the expense of completeness. The intent is to provide the reader with an introduction to the language that will
facilitate the writing of early programs and the reading of later chapters.
1.1 Hello, world
The canonical “Hello, world” program can be written in C# as follows:
using System;
class Hello
{
static void Main() {
Console.WriteLine("Hello, world");
}
}
The default file extension for C# programs is .cs, as in hello.cs. Such a program can be compiled with the
command line directive
csc hello.cs
which produces an executable program named hello.exe. The output of the program is:
Hello, world
Close examination of this program is illuminating:
• The using System; directive references a namespace called System that is provided by the .NET
runtime. This namespace contains the Console class referred to in the Main method. Namespaces
provide a hierarchical means of organizing the elements of a class library. A “using” directive enables
unqualified use of the members of a namespace. The “Hello, world” program uses
Console.WriteLine as a shorthand for System.Console.WriteLine. What do these identifiers
denote? System is a namespace, Console is a class defined in that namespace, and WriteLine is a
static method defined on that class.
C# LANGUAGE REFERENCE
2 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
• The Main function is a static member of the class Hello. Functions and variables are not supported at
the global level; such elements are always contained within type declarations (e.g., class and struct
declarations).
• The “Hello, world” output is produced through the use of a class library. C# does not itself provide a
class library. Instead, C# uses a common class library that is also used by other languages such as Visual
Basic and Visual C++.
For C and C++ developers, it is interesting to note a few things that do not appear in the “Hello, world”
program.
• The program does not use either “::” or “->” operators. The “::” is not an operator in C# at all, and
the “->” operator is used in only a small fraction of C# programs. C# programs use “.” as a separator in
compound names such as Console.WriteLine.
• The program does not contain forward declarations. Forward declarations are never needed in C#
programs, as declaration order is not significant.
• The program does not use #include to import program text. Dependencies between programs are
handled symbolically rather than with program text. This system eliminates barriers between programs
written in different languages. For example, the Console class could be written in C# or in some other
language.
1.2 Automatic memory management
Manual memory management requires developers to manage the allocation and de-allocation of blocks of
memory. Manual memory management is both time consuming and difficult. C# provides automatic memory
management so that developers are freed from this burdensome task. In the vast majority of cases, this automatic
memory management increases code quality and enhances developer productivity without negatively impacting
either expressiveness or performance.
The example
using System;
public class Stack
{
private Node first = null;
public bool Empty {
get {
return (first == null);
}
}
public object Pop() {
if (first == null)
throw new Exception("Can't Pop from an empty Stack.");
else {
object temp = first.Value;
first = first.Next;
return temp;
}
}
public void Push(object o) {
first = new Node(o, first);
}
Chapter 1 Introduction
Copyright Microsoft Corporation 1999-2000. All Rights Reserved. 3
class Node
{
public Node Next;
public object Value;
public Node(object value): this(value, null) {}
public Node(object value, Node next) {
Next = next;
Value = value;
}
}
}
shows a Stack class implemented as a linked list of Node instances. Node instances are created in the Push
method and are garbage collected when no longer needed. A Node instance becomes eligible for garbage
collection when it is no longer possible for any code to access it. For instance, when an item is removed from
the Stack, the associated Node instance becomes eligible for garbage collection.
The example
class Test
{
static void Main() {
Stack s = new Stack();
for (int i = 0; i < 10; i++)
s.Push(i);
while (!s.Empty)
Console.WriteLine(s.Pop());
}
}
shows a test program that uses the Stack class. A Stack is created and initialized with 10 elements, and then
assigned the value null. Once the variable s is assigned null, the Stack and the associated 10 Node instances
become eligible for garbage collection. The garbage collector is permitted to clean up immediately, but is not
required to do so.
For developers who are generally content with automatic memory management but sometimes need fine-grained
control or that extra iota of performance, C# provides the ability to write “unsafe” code. Such code can deal
directly with pointer types, and fix objects to temporarily prevent the garbage collector from moving them. This
“unsafe” code feature is in fact “safe” feature from the perspective of both developers and users. Unsafe code
must be clearly marked in the code with the modifier unsafe, so developers can't possibly use unsafe features
accidentally, and the C# compiler and the execution engine work together to ensure that unsafe code cannot
masquerade as safe code.
The example
using System;
C# LANGUAGE REFERENCE
4 Copyright Microsoft Corporation 1999-2000. All Rights Reserved.
class Test
{
unsafe static void WriteLocations(byte[] arr) {
fixed (byte *p_arr = arr) {
byte *p_elem = p_arr;
for (int i = 0; i < arr.Length; i++) {
byte value = *p_elem;
string addr = int.Format((int) p_elem, "X");
Console.WriteLine("arr[{0}] at 0x{1} is {2}", i, addr, value);
p_elem++;
}
}
}
static void Main() {
byte[] arr = new byte[] {1, 2, 3, 4, 5};
WriteLocations(arr);
}
}
shows an unsafe method named WriteLocations that fixes an array instance and uses pointer manipulation to
iterate over the elements and write out the index, value, and location of each. One possible output of the
program is:
arr[0] at 0x8E0360 is 1
arr[1] at 0x8E0361 is 2
arr[2] at 0x8E0362 is 3
arr[3] at 0x8E0363 is 4
arr[4] at 0x8E0364 is 5
but of course the exact memory locations are subject to change.
see you soon in the second lecture.