C#'s Philosophy
C# is a modern, general-purpose, and powerful language which applies two
theories:
- Object orientation
- Type safety
C# is an object-oriented language which exploits
benefits from classic object-oriented paradigm while eliminating its limitations
to shape modern, powerful object orientation model. In particular, C# supports
following features:
- Modeling and abstraction
- Encapsulation
- Composition and inheritance
- Polymorphism and generic type
C# allows programmers modeling programming
objects from real-life objects by enabling them to create types. Each type
contains only state and behaviors that are expected for application business. A
type's state and behaviors are known as members of that type. Having type
declarations, you could write business logic by initializing type's instances or
objects and let them communicate with each other or in some cases you could even
let types themselves interact directly.
While creating a type in C# you could specify which members are available
outside that type and which members are not. You do so by applying modifiers on
members and types. In addition, you also use modifiers to adjust other
implementation aspects such as indicating a member is available at type-level or
object-level. All this process is known as encapsulation.
Like real-life objects, programming objects usually depend on other objects.
There are two relationships between objects in C#. An object can contain another
one such as a Customer object can include contact information that is an object
of Contact type. This relationship is known as composition. An object also could
be derived from another one, for example an Apple object is derived from Fruit
object. This relationship is known as inheritance. Both relationships make our
programs more meaningful and easier to implement. A note is that unlike
real-life objects or older OO programming languages, C# supports only single
inheritance and eliminates multiple inheritances. This because multiple
inheritances are not meaningful in most cases and using them adds more overheads
on type resolving process.
Base on single inheritance, you could write certain code that work on base type
and let runtime engine determines what particular derived type you intended to
use in current context when the application runs. This feature is called
polymorphism and is the most powerful feature of object-oriented programming.
The goal to which polymorphism targets, is to help programmers to create generic
code that make their programs more compact and effective. In addition, C# adds a
further step in creating generic code when it introduces a so-called generic
type feature. Generic type or generic for short is a way to create parameterized
types so that they can be used to create concrete types for your needs. You will
see generic is used very popular in generic collections and in some cases else.
So far, we know that C# is all about types creating and therefore, using types
in a right way is an important issue. In earlier OO languages such as C++ you
could write code like following but don't get errors until the application
executes.
Customer customer = new Customer();
customer.Order();
Product product = customer;
product.Order();
C# eliminates this class of errors by enforcing a mechanism called type safety.
In particular, C# requires programmers follow rules when working on types. For
example, they must explicitly declare a particular type of a variable or they
can not assign between incompatible variables or they can call only a type's
members on an object of that type. Since this, C# is also called static typed
language or strongly typed language. Not only does C# provide strict rules, but
also it executes type checking at compile-time and run-time to ensure no
violations happen. With type safety, C# reduces a large of subtle errors,
improves programmer's productiveness, and makes program more robustness,
reliability and readability.
C# and .NET Framework
C# is not created as a stand-alone language. Instead, it is a language used
within the .NET Framework which is a next generation platform for writing modern
applications.
By using .NET Framework, you get some important benefits as follows:
- Support object orientation model
- Support cross-language and cross-platform.
- Support runtime services such as
automatically memory management, code security, threading, exception
handling.
- Support types allowing developers to
create any type of applications including Windows applications, Web
applications, Web services, Smart device applications, and Cloud
applications on Windows Azure.
To provide functionalities listed above, .NET
Framework is composed from 3 components:
- A runtime execution engine is called
Common Language Runtime (CLR)
- A vast of libraries is called Framework
Class Library (FCL)
- A set of tools including Visual Studio,
compilers, utilities, etc.
In fact, .NET Framework is a Microsoft's
implementation of ECMA 335 standard. This standard specifies a runtime
infrastructure (commonly known as Common Language Infrastructure – CLI) required
to execute so-called managed code, to allow different libraries and languages to
work together seamlessly.
CLI defines an execution engine or virtual machine called Virtual Execution
System (VES) as its heart. VES knows nothing but how to manage, load and execute
managed code. CLI requires any language want to be used with VES must have a
compiler that can compile source code to managed code.
The format of managed code has to comply with the standard CLI defines that is
called Common Intermediate Language (CIL). In addition, managed code has to
packed in packages called assemblies along with metadata is used to describe
information about code and assemblies as well. The CLI also outlines the file
format of assemblies to ensure cross-platform compatibility.
To ensure cross-language interoperability, CLI defines a unified types system
called Common Type System (CTS). CTS includes common data types that are shared
among languages use it. In addition, all common types must derive from a mother
type that is, for example, System.Object in .NET Framework
The CTS is a necessary but not enough part to ensure code written by different
languages can work together seamlessly. Because different languages have
different implementation details, it is possible to have a piece of code that is
valid in a language but invalid in another. For example, C# is a case-sensitive
language while VB.NET is not. Therefore, if you have a piece of code with two
variables have same name but different cases then that code can work in C# but
cannot run in VB.NET. The result of that is VB.NET developer cannot use your
code in his program.
To absolutely ensure cross-language feature can be used, CLI defines another
part called Common Language Specification (CLS). It is a set of rules on which
all languages must follow to create types marked CLS-compliant that means all
languages will be able to interact with those types. Obviously, one of rules
will be "create only types which are compatible with CTS" and another one will
be "Do not create two or more variables that its names are different by only
cases".
C#'s Evolution
From that time it was born, C# immediately became a preferred choice of many
.NET developers due to its power and easiness. However, it is not entirely
perfect language at that time and this is still true today. Realizing that and
over many years, the C# design team at Microsoft have continually improved it by
adding more advanced features.
The following is a briefly description about changes from C# 2.0 to C# 4.
Changes in C# 2.0
Generic | A way to create parameterized types |
Iterator |
A way to make it easier to support foreach iteration in a class or
struct without having to implement the entire IEnumerable interface |
Partial class |
A way to define a class in multiple files |
Nullable type |
A way to allow a value type can contain null value. It is useful when
working with database's data types |
Anonymous method |
A way to create inline methods at anywhere a delegate is expected. It
eliminates the need to define a new method. |
Static class |
A safe and convenient way to create a class containing only static
members that cannot be instantiated. |
Friend assembly |
A mechanism to access an internal type or internal member in an assembly |
Changes in C# 3.0
Lambda expression |
A replacement of anonymous method. It is inspired from functional
programming discipline. It is especially useful in LINQ |
Extension method |
A mechanism allows an existing type to be extended with new methods,
without altering the definition of the original type. It is also used to
make LINQ available |
Implicit typing |
A way to declare variables with var keyword. It is used very popular in
LINQ |
Anonymous type |
A way to create inline object to store a set of values. It is used
primarily with LINQ |
Automatic properties |
A way to make properties with no additional logic is required |
Object and collection initializer |
A way to initialize objects or collections at creation time without
having to explicitly invoke a constructor. |
Partial method |
A way to create a signature and an implementation of a method in a
partial class |
Changes in C# 4.0
Dynamic type |
A way to allow late binding to a type and therefore bypass type checking
at compile-time. It is inspired from dynamic typed languages. It is
useful in some special cases such as when working with COM API, with
IronPython, or with HTML DOM |
Named and optional argument |
Named arguments
enable you to specify an argument by parameter name rather than by the
parameter's position in the parameter list.
Optional arguments enable you to omit arguments for some
parameters. |
Covariance and contravariance |
A way to enable
implicit reference conversion of generic type parameters for interface
and delegate types. It helps writing generic code more naturally and
allows safe type enforcement |