C# is a language built specifically to program the Microsoft .NET Framework. The .NET Framework consists of a runtime environment called the Common Language Runtime (CLR), and a set of class libraries, which provide a rich development platform that can be exploited by a variety of languages and tools.
Programming languages have strengths in different areas. Some languages are powerful but can be bug-prone and difficult to work with, while others are simpler but can be limiting in terms of functionality or performance. C# is a new language designed to provide an optimum blend of simplicity, expressiveness, and performance.
Many features of C# were designed in response to the strengths and weaknesses of other languages, particularly Java and C++. The C# language specification was written by Anders Hejlsberg and Scott Wiltamuth. Anders Hejlsberg is famous in the programming world for creating the Turbo Pascal compiler and leading the team that designed Delphi.
Key features of the C# language include the following:
An excellent way to manage complexity in a program is to subdivide it into several interacting components, some of which can be used in multiple scenarios. C# has been designed to make component building easy and provides component-oriented language constructs such as properties, events, and declarative constructs called attributes.
Everything pertaining to a declaration in C# is localized to
the declaration itself, rather than being spread across several
source files or several places within a source file. Types do not
require additional declarations in separate header or Interface
Definition Language (IDL) files, a property’s get/set
methods are logically grouped,
documentation is embedded directly in a declaration, etc.
Furthermore, because declaration order is irrelevant, types don’t
require a separate stub declaration to be used by another
type.
C# provides features such as explicit interface implementations, hiding inherited members, and read-only modifiers, which help new versions of a component work with older components that depend on it.
C# is type-safe, which ensures that a variable can be accessed only through the type associated with that variable. This encapsulation encourages good programming design and eliminates potential bugs or security breaches by making it impossible for one variable to inadvertently or maliciously overwrite another.
All C# types (including primitive types) derive from a single base type, providing a unified type system. This means all types—structs, interfaces, delegates, enums, and arrays—share the same basic functionality, such as the ability to be converted to a string, serialized, or stored in a collection.
C# relies on a runtime that performs automatic memory management. This frees programmers from disposing objects, which eliminates problems such as dangling pointers, memory leaks, and coping with circular references.
However, C# does not eliminate pointers: it merely makes
them unnecessary for most programming tasks. For
performance-critical hotspots and interoperability, pointers may
be used, but they are only permitted in unsafe
blocks that require a high
security permission to execute.
A big advantage of C# over other languages, particularly traditionally compiled languages such as C++, is its close fit with the .NET CLR. Many aspects of C# alias the CLR, especially its type system, memory-management model, and exception-handling mechanism.
Of fundamental importance to the .NET Framework is the fact that programs are executed within a managed execution environment provided by the Common Language Runtime. The CLR greatly improves runtime interactivity between programs, portability, security, development simplicity, and cross-language integration, and provides an excellent foundation for a rich set of class libraries.
Absolutely key to these benefits is the way .NET programs are compiled. Each language targeting .NET compiles source code into metadata and Microsoft Intermediate Language (MSIL) code. Metadata includes a complete specification for a program including all its types, apart from the actual implementation of each function. These implementations are stored as MSIL, which is machine-independent code that describes the instructions of a program. The CLR uses this “blueprint” to bring a .NET program to life at runtime, providing services far beyond what is possible with the traditional approach—compiling code directly to assembly language.
Key features of the CLR include the following:
Programs can richly interact with each other at runtime through their metadata. A program can search for new types at runtime, then instantiate and invoke methods on those types.
Programs can be run without recompiling on any operating system and processor combination that supports the CLR. A key element of this platform independence is the runtime’s JIT ( Just-In-Time) Compiler, which compiles the MSIL code it is fed to native code that runs on the underlying platform.
Security considerations permeate the design of the .NET Framework. The key to making this possible is CLR’s ability to analyze MSIL instructions as being safe or unsafe.
An assembly is a completely self-describing package that contains all the metadata and MSIL of a program. Deployment can be as easy as copying the assembly to the client computer.
An assembly can function properly with new versions of assemblies it depends on without recompilation. Key to making this possible is the ability to resolve all type references though metadata.
The CLR provides many features that greatly simplify development, including services such as garbage collection, exception handling, debugging, and profiling.
The Common Type System (CTS) of the CLR defines the types that can be expressed in metadata and MSIL and the possible operations that can be performed on those types. The CTS is broad enough to support many different languages including Microsoft languages, such as C#, VB.NET, and Visual C++ .NET, and such third-party languages as COBOL, Eiffel, Haskell, Mercury, ML, Oberon, Python, Smalltalk, and Scheme.
The Common Language Specification (CLS) defines a subset of the CTS, which provides a common standard that enables .NET languages to share and extend each other’s libraries. For instance, an Eiffel programmer can create a class that derives from a C# class and override its virtual methods.
The CLR provides interoperation with the vast base of existing software written in COM and C. .NET types can be exposed as COM types, and COM types can be imported as .NET types. In addition, the CLR provides PInvoke, which is a mechanism that enables C functions, structs, and callbacks to be easily used from within in a .NET program.
The .NET Framework provides the .NET Framework Class Library (FCL), which can be used by all languages. The FCL offers features ranging from core functionality of the runtime, such as threading and runtime manipulation of types (reflection), to types that provide high-level functionality, such as data access, rich client support, and web services (whereby code can even be embedded in a web page). C# has almost no built-in libraries; it uses the FCL instead.
Here is a simple C# program:
namespace FirstProgram { using System; class Test { static void Main ( ) { Console.WriteLine ("Welcome to C#!"); } } }
A C# program is composed of types (typically classes) that we
organize into namespaces. Each type contains function members (typically
methods), as well as data members (typically fields). In our program, we
define a class named Test
that
contains a method, named Main
, that
writes Welcome
to
C#!
to
the Console
window. The Console
class encapsulates standard
input/output functionality, providing methods such as WriteLine
. To use types from another
namespace, we use the using
directive. Since the Console
class
resides in the System
namespace, we
write using
System
; similarly, types from other namespaces
could use our Test
class by including
the following statement: using
FirstProgram;
.
To compile this program into an executable, paste it into a text
file, save it as Test.cs, then type
csc Test.cs
in the command
prompt. This compiles the program into an executable called Test.exe. Add the /debug
option to the csc
command line to include debugging symbols
in the output. This will let you run your program under a debugger and
get meaningful stack traces that include line numbers.
.NET executables contain a small CLR host created by the C#
compiler. The host starts the CLR and loads your application, starting
at the Main
entry point.
Note that Main
must be specified as
static
.
In C#, there are no standalone functions; functions are always
associated with a type, or as we will see, instances of that type. Our
program is simple and makes use of only static members, which means the
member is associated with its type, rather than instances of its type.
In addition, we make use of only void methods, which means these methods
do not return a value. Of final note is that C# recognizes a method
named Main
as the default entry point of
execution.