05 January 2011
The C# Programming Language. What is C# ?
- What is .NET ?
programming language, C# (pronounced “see sharp”), specifically for this new platform. C# is a programming
language whose core syntax looks very similar to the syntax of Java. However, to call C# a Java rip-off is inaccurate. Both C# and Java are members of the C family of programming languages
(C, Objective C, C++, etc.) and therefore share a similar syntax. Just as Java is in many ways a
cleaned-up version of C++, C# can be viewed as a cleaned-up version of Java.
The truth of the matter is that many of C#’s syntactic constructs are modeled after various
aspects of Visual Basic 6.0 and C++. For example, like VB6, C# supports the notion of formal type
properties (as opposed to traditional getter and setter methods) and the ability to declare methods
taking a varying number of arguments (via parameter arrays). Like C++, C# allows you to overload
operators, as well as to create structures, enumerations, and callback functions (via delegates).
Due to the fact that C# is a hybrid of numerous languages, the result is a product that is as syntactically
clean—if not cleaner—than Java, is about as simple as VB6, and provides just about as
much power and flexibility as C++ (without the associated ugly bits). Here is a partial list of core C#
features that are found in all versions of the language:
• No pointers required! C# programs typically have no need for direct pointer manipulation
(although you are free to drop down to that level if absolutely necessary).
• Automatic memory management through garbage collection. Given this, C# does not support
a delete keyword.
• Formal syntactic constructs for classes, interfaces, structures, enumerations, and delegates.
• The C++-like ability to overload operators for a custom type, without the complexity (e.g.,
making sure to “return *this to allow chaining” is not your problem).
• Support for attribute-based programming. This brand of development allows you to annotate
types and their members to further qualify their behavior.
With the release of .NET 2.0 (circa 2005), the C# programming language was updated to support
numerous new bells and whistles, most notably the following:
• The ability to build generic types and generic members. Using generics, you are able to build
very efficient and type-safe code that defines numerous “placeholders” specified at the time
you interact with the generic item.
• Support for anonymous methods, which allow you to supply an inline function anywhere a
delegate type is required.
• Numerous simplifications to the delegate/event model, including covariance, contravariance,
and method group conversion.
• The ability to define a single type across multiple code files (or if necessary, as an in-memory
representation) using the partial keyword.
As you might guess, .NET 3.5 adds even more functionality to the C# programming language
(C# 2008, to be exact), including the following features:
• Support for strongly typed queries (a la LINQ, or Language Integrated Query) used to interact
with various forms of data
• Support for anonymous types, which allow you to model the “shape” of a type rather than its
behavior
• The ability to extend the functionality of an existing type using extension methods
• Inclusion of a lambda operator (=>), which even further simplifies working with .NET delegate
types
• A new object initialization syntax, which allows you to set property values at the time of
object creation
Perhaps the most important point to understand about the C# language is that it can only produce
code that can execute within the .NET runtime (you could never use C# to build a native COM
server or an unmanaged Win32 API application). Officially speaking, the term used to describe the
code targeting the .NET runtime is managed code. The binary unit that contains the managed code
is termed an assembly (more details on assemblies in just a bit in the section “An Overview of .NET
Assemblies”). Conversely, code that cannot be directly hosted by the .NET runtime is termed
unmanaged code.
The Philosophy of .NET. Why we need .NET ?
Every few years or so, the modern-day programmer must be willing to perform a self-inflicted
knowledge transplant to stay current with the new technologies of the day. The languages (C++,
Visual Basic 6.0, Java), frameworks (OWL, MFC, ATL, STL), architectures (COM, CORBA, EJB), and
APIs (such as .NET’s Windows Forms and GDI+ libraries) that were touted as the silver bullets of
software development eventually become overshadowed by something better or at the very least
something new. Regardless of the frustration you can feel when upgrading your internal knowledge
base, it is frankly unavoidable. To this end, the goal of this book is to examine the details of Microsoft’s
current offering within the landscape of software engineering: the .NET platform and the C# programming
language.
The point of this chapter is to lay the conceptual groundwork for the remainder of the book.
Here you will find a high-level discussion of a number of .NET-related topics such as assemblies, the
common intermediate language (CIL), and just-in-time (JIT) compilation. In addition to previewing
some key features of the C# programming language, you will also come to understand the
relationship between various aspects of the .NET Framework, such as the common language runtime
(CLR), the Common Type System (CTS), and the Common Language Specification (CLS).
This chapter also provides you with a survey of the functionality supplied by the .NET
base class libraries, sometimes abbreviated as the BCL or alternatively as the FCL (being the
Framework class libraries). Finally, this chapter overviews the language-agnostic and platformindependent
nature of the .NET platform(yes it’s true, .NET is not confined to the Windows
operating system). As you would hope, all of these topics are explored in further detail throughout
the remainder of this text.
Understanding the Previous State of Affairs
Before examining the specifics of the .NET universe, it’s helpful to consider some of the issues that
motivated the genesis of Microsoft’s current platform. To get in the proper mind-set, let’s begin this
chapter with a brief and painless history lesson to remember our roots and understand the limitations
of the previous state of affairs (after all, admitting you have a problem is the first step toward
finding a solution). After completing this quick tour of life as we knew it, we turn our attention to
the numerous benefits provided by C# and the .NET platform.
Life As a C/Win32 API Programmer
Traditionally speaking, developing software for the Windows family of operating systems involved
using the C programming language in conjunction with the Windows application programming
interface (API). While it is true that numerous applications have been successfully created using this
time-honored approach, few of us would disagree that building applications using the raw API is a
complex undertaking.
The first obvious problem is that C is a very terse language. C developers are forced to contend
with manual memory management, ugly pointer arithmetic, and ugly syntactical constructs. Furthermore,
given that C is a structured language, it lacks the benefits provided by the object-oriented
approach (can anyone say spaghetti code?). When you combine the thousands of global functions
and data types defined by the Win32 API to an already formidable language, it is little wonder that
there are so many buggy applications floating around today.
Life As a C++/MFC Programmer
One vast improvement over raw C/API development is the use of the C++ programming language.
In many ways, C++ can be thought of as an object-oriented layer on top of C. Thus, even though
C++ programmers benefit from the famed “pillars of OOP” (encapsulation, inheritance, and polymorphism),
they are still at the mercy of the painful aspects of the C language (e.g., manual memory
management, ugly pointer arithmetic, and ugly syntactical constructs).
Despite its complexity, many C++ frameworks exist today. For example, the Microsoft Foundation
Classes (MFC) provide the developer with a set of C++ classes that facilitate the construction of
Win32 applications. The main role of MFC is to wrap a “sane subset” of the raw Win32 API behind a
number of classes, magic macros, and numerous code-generation tools (a.k.a. wizards). Regardless
of the helpful assistance offered by the MFC framework (as well as many other C++-based windowing
toolkits), the fact of the matter is that C++ programming remains a difficult and error-prone
experience, given its historical roots in C.
Life As a Visual Basic 6.0 Programmer
Due to a heartfelt desire to enjoy a simpler lifestyle, many programmers have shifted away from the
world of C(++)-based frameworks to kinder, gentler languages such as Visual Basic 6.0 (VB6). VB6 is
popular due to its ability to build complex user interfaces, code libraries (e.g., COM servers), and
data access logic with minimal fuss and bother. Even more than MFC, VB6 hides the complexities
of the raw Win32 API from view using a number of integrated code wizards, intrinsic data types,
classes, and VB-specific functions.
The major downfall of VB6 (which has been rectified given the advent of the .NET platform) is
that it is not a fully object-oriented language; rather, it is “object aware.” For example, VB6 does not
allow the programmer to establish “is-a” relationships between types (i.e., no classical inheritance)
and has no intrinsic support for parameterized class construction. Moreover, VB6 doesn’t provide
the ability to build multithreaded applications unless you are willing to drop down to low-level
Win32 API calls (which is complex at best and dangerous at worst).
Life As a Java/J2EE Programmer
Enter Java. Java is an object-oriented programming language that has its syntactic roots in C++. As
many of you are aware, Java’s strengths are far greater than its support for platform independence.
Java (as a language) cleans up many unsavory syntactical aspects of C++. Java (as a platform)
provides programmers with a large number of predefined “packages” that contain various type
definitions. Using these types, Java programmers are able to build “100% Pure Java” applications
complete with database connectivity, messaging support, web-enabled front ends, and a rich
desktop user interface.
Although Java is a very elegant language, one potential problem is that using Java typically
means that you must use Java front-to-back during the development cycle. In effect, Java offers little
hope of language integration, as this goes against the grain of Java’s primary goal (a single programming
language for every need). In reality, however, there are millions of lines of existing code out there in the world that would ideally like to commingle with newer Java code. Sadly, Java makes this
task problematic. While Java does provide a limited ability to access non-Java APIs, there is little
support for true cross-language integration.
The .NET Solution
So much for the brief history lesson. The bottom line is that life as a Windows programmer has been
tough. The .NET Framework is a rather radical and brute-force approach to making our lives easier.
The solution proposed by .NET is “Change everything” (sorry, you can’t blame the messenger for the
message). As you will see during the remainder of this book, the .NET Framework is a completely
new model for building systems on the Windows family of operating systems, as well as on numerous
non-Microsoft operating systems such as Mac OS X and various Unix/Linux distributions. To
set the stage, here is a quick rundown of some core features provided courtesy of .NET:
• Comprehensive interoperability with existing code: This is (of course) a good thing. Existing
COM binaries can commingle (i.e., interop) with newer .NET binaries and vice versa. Also,
PlatformInvocation Services (PInvoke) allows you to call C-based libraries (including the
underlying API of the operating system) from .NET code.
• Complete and total language integration: .NET supports cross-language inheritance, crosslanguage
exception handling, and cross-language debugging of code.
• A common runtime engine shared by all .NET-aware languages: One aspect of this engine is a
well-defined set of types that each .NET-aware language “understands.”
• A comprehensive base class library: This library provides shelter from the complexities of raw
API calls and offers a consistent object model used by all .NET-aware languages.
• No more COM plumbing: IClassFactory, IUnknown, IDispatch, IDL code, and the evil variantcompliant
data types (BSTR, SAFEARRAY, and so forth) have no place in a .NET binary.
• A truly simplified deployment model: Under .NET, there is no need to register a binary unit
into the system registry. Furthermore, .NET allows multiple versions of the same *.dll to
exist in harmony on a single machine.
As you can most likely gather from the previous bullet points, the .NET platform has nothing to
do with COM (beyond the fact that both frameworks originated from Microsoft). In fact, the only
way .NET and COM types can interact with each other is using the interoperability layer.
knowledge transplant to stay current with the new technologies of the day. The languages (C++,
Visual Basic 6.0, Java), frameworks (OWL, MFC, ATL, STL), architectures (COM, CORBA, EJB), and
APIs (such as .NET’s Windows Forms and GDI+ libraries) that were touted as the silver bullets of
software development eventually become overshadowed by something better or at the very least
something new. Regardless of the frustration you can feel when upgrading your internal knowledge
base, it is frankly unavoidable. To this end, the goal of this book is to examine the details of Microsoft’s
current offering within the landscape of software engineering: the .NET platform and the C# programming
language.
The point of this chapter is to lay the conceptual groundwork for the remainder of the book.
Here you will find a high-level discussion of a number of .NET-related topics such as assemblies, the
common intermediate language (CIL), and just-in-time (JIT) compilation. In addition to previewing
some key features of the C# programming language, you will also come to understand the
relationship between various aspects of the .NET Framework, such as the common language runtime
(CLR), the Common Type System (CTS), and the Common Language Specification (CLS).
This chapter also provides you with a survey of the functionality supplied by the .NET
base class libraries, sometimes abbreviated as the BCL or alternatively as the FCL (being the
Framework class libraries). Finally, this chapter overviews the language-agnostic and platformindependent
nature of the .NET platform(yes it’s true, .NET is not confined to the Windows
operating system). As you would hope, all of these topics are explored in further detail throughout
the remainder of this text.
Understanding the Previous State of Affairs
Before examining the specifics of the .NET universe, it’s helpful to consider some of the issues that
motivated the genesis of Microsoft’s current platform. To get in the proper mind-set, let’s begin this
chapter with a brief and painless history lesson to remember our roots and understand the limitations
of the previous state of affairs (after all, admitting you have a problem is the first step toward
finding a solution). After completing this quick tour of life as we knew it, we turn our attention to
the numerous benefits provided by C# and the .NET platform.
Life As a C/Win32 API Programmer
Traditionally speaking, developing software for the Windows family of operating systems involved
using the C programming language in conjunction with the Windows application programming
interface (API). While it is true that numerous applications have been successfully created using this
time-honored approach, few of us would disagree that building applications using the raw API is a
complex undertaking.
The first obvious problem is that C is a very terse language. C developers are forced to contend
with manual memory management, ugly pointer arithmetic, and ugly syntactical constructs. Furthermore,
given that C is a structured language, it lacks the benefits provided by the object-oriented
approach (can anyone say spaghetti code?). When you combine the thousands of global functions
and data types defined by the Win32 API to an already formidable language, it is little wonder that
there are so many buggy applications floating around today.
Life As a C++/MFC Programmer
One vast improvement over raw C/API development is the use of the C++ programming language.
In many ways, C++ can be thought of as an object-oriented layer on top of C. Thus, even though
C++ programmers benefit from the famed “pillars of OOP” (encapsulation, inheritance, and polymorphism),
they are still at the mercy of the painful aspects of the C language (e.g., manual memory
management, ugly pointer arithmetic, and ugly syntactical constructs).
Despite its complexity, many C++ frameworks exist today. For example, the Microsoft Foundation
Classes (MFC) provide the developer with a set of C++ classes that facilitate the construction of
Win32 applications. The main role of MFC is to wrap a “sane subset” of the raw Win32 API behind a
number of classes, magic macros, and numerous code-generation tools (a.k.a. wizards). Regardless
of the helpful assistance offered by the MFC framework (as well as many other C++-based windowing
toolkits), the fact of the matter is that C++ programming remains a difficult and error-prone
experience, given its historical roots in C.
Life As a Visual Basic 6.0 Programmer
Due to a heartfelt desire to enjoy a simpler lifestyle, many programmers have shifted away from the
world of C(++)-based frameworks to kinder, gentler languages such as Visual Basic 6.0 (VB6). VB6 is
popular due to its ability to build complex user interfaces, code libraries (e.g., COM servers), and
data access logic with minimal fuss and bother. Even more than MFC, VB6 hides the complexities
of the raw Win32 API from view using a number of integrated code wizards, intrinsic data types,
classes, and VB-specific functions.
The major downfall of VB6 (which has been rectified given the advent of the .NET platform) is
that it is not a fully object-oriented language; rather, it is “object aware.” For example, VB6 does not
allow the programmer to establish “is-a” relationships between types (i.e., no classical inheritance)
and has no intrinsic support for parameterized class construction. Moreover, VB6 doesn’t provide
the ability to build multithreaded applications unless you are willing to drop down to low-level
Win32 API calls (which is complex at best and dangerous at worst).
Life As a Java/J2EE Programmer
Enter Java. Java is an object-oriented programming language that has its syntactic roots in C++. As
many of you are aware, Java’s strengths are far greater than its support for platform independence.
Java (as a language) cleans up many unsavory syntactical aspects of C++. Java (as a platform)
provides programmers with a large number of predefined “packages” that contain various type
definitions. Using these types, Java programmers are able to build “100% Pure Java” applications
complete with database connectivity, messaging support, web-enabled front ends, and a rich
desktop user interface.
Although Java is a very elegant language, one potential problem is that using Java typically
means that you must use Java front-to-back during the development cycle. In effect, Java offers little
hope of language integration, as this goes against the grain of Java’s primary goal (a single programming
language for every need). In reality, however, there are millions of lines of existing code out there in the world that would ideally like to commingle with newer Java code. Sadly, Java makes this
task problematic. While Java does provide a limited ability to access non-Java APIs, there is little
support for true cross-language integration.
The .NET Solution
So much for the brief history lesson. The bottom line is that life as a Windows programmer has been
tough. The .NET Framework is a rather radical and brute-force approach to making our lives easier.
The solution proposed by .NET is “Change everything” (sorry, you can’t blame the messenger for the
message). As you will see during the remainder of this book, the .NET Framework is a completely
new model for building systems on the Windows family of operating systems, as well as on numerous
non-Microsoft operating systems such as Mac OS X and various Unix/Linux distributions. To
set the stage, here is a quick rundown of some core features provided courtesy of .NET:
• Comprehensive interoperability with existing code: This is (of course) a good thing. Existing
COM binaries can commingle (i.e., interop) with newer .NET binaries and vice versa. Also,
PlatformInvocation Services (PInvoke) allows you to call C-based libraries (including the
underlying API of the operating system) from .NET code.
• Complete and total language integration: .NET supports cross-language inheritance, crosslanguage
exception handling, and cross-language debugging of code.
• A common runtime engine shared by all .NET-aware languages: One aspect of this engine is a
well-defined set of types that each .NET-aware language “understands.”
• A comprehensive base class library: This library provides shelter from the complexities of raw
API calls and offers a consistent object model used by all .NET-aware languages.
• No more COM plumbing: IClassFactory, IUnknown, IDispatch, IDL code, and the evil variantcompliant
data types (BSTR, SAFEARRAY, and so forth) have no place in a .NET binary.
• A truly simplified deployment model: Under .NET, there is no need to register a binary unit
into the system registry. Furthermore, .NET allows multiple versions of the same *.dll to
exist in harmony on a single machine.
As you can most likely gather from the previous bullet points, the .NET platform has nothing to
do with COM (beyond the fact that both frameworks originated from Microsoft). In fact, the only
way .NET and COM types can interact with each other is using the interoperability layer.
Subscribe to:
Posts (Atom)