Share via


TLS320: C# Language Enhancements

Generics

Generics are strongly-typed template mechanism. They enable you to create
classes such as collections without requiring boxing. Generics offer type checking,
no boxing and no downcasts, as well as reducing code bloat. Generics are instantiated
at run-time, not compile-time and are checked at declaration, not instantiation. (In
comparison, C++ templates are created at compile-time and checked when instantiated.)
The strongly-typed nature of generics thus results in fewer hard-to-debug errors and
better runtime type information. Generics are being introduced in Java, but they are
purely syntactic sugar - when compiled, all the type parameters are thrown away and
replaced with casting etc.

Type parameters can be applied to class, struct, interface and delegate types. You
can declare:

    class Dictionary<K, V> { ... }
   Dictionary <string, Customer> customerLookupTable;
   Dictionary <string, List<Order>> orderLookupTable; 

Type parameters can also be applied to methods:

    public static void SortArray<T>(T[] array) { ... }
   string names[];
   SortArray(names); // notice that the type parameter is inferred

Type parameters can also have constraints, e.g.

    class Dictionary<K, V> where K : IComparable, new()

Here K must implement IComparable and a parameterless public default constructor.
A constraint such as this can be verified at compile-time.

Generics are invariant, meaning that they have no intrinsic connection to each other
within the class hierarchy. This is a deliberate decision due to the performance cost
of implementing covariance. Interfaces can be used for type neutrality, however. On
the subject of performance, a List<int> runs over twice as fast as the existing
alternative - an ArrayList containing int objects. This is because it no longer requires
all the boxing and unboxing to take place.

You are not permitted to assign null to a generic field, since there are no guarantees
that it is nullable. Instead, you can write something like:

    T y = T.default; // 0 or null, depending on val/ref

Generics are not just a C# language feature - they are embedded deep within the CLR.
There's a new namespace System.Collections.Generic which contains generic implementations
of the standard classes, interfaces, base classes. Reflection is also supported on
generics.

One fantastic new class is System.Nullable<T>, which provides nullability for
any type. This is a struct that combines a T with a bool; there are implicit conversions
from null to Nullable<T> and T to Nullable<T>.

Anonymous Methods

Today, event handlers are a lot of work. You have to create a separate method
to handle an event. Instead, anonymous methods allow code blocks to be inserted in
place of a delegate. The delegate type is automatically inferred. If you don't care
about the arguments that the delegate is providing to you, you can provide a parameterless
method; alternatively you can add parameters.

For instance:

    button.Click += delegate(object sender, EventArgs e) {
      MessageBox.Show(((Button)sender).Text);
   };

Anonymous methods are more or less the same as lambda-functions in Lisp - a higher-order
function, to use functional programming terminology.

Iterators

The foreach statement relies on an enumerator pattern. This is hard to write,
but it makes the enumeration itself easy to access. Iterators provide a method that
incrementally computes and returns a sequence of values. For instance:

    public IEnumerator GetEnumerator() {
      for (int i=0; i < count; i++) 
      {
         yield return elements[i]; 
      }
   }

You can use these to implement the GetEnumerator() method or to create another method
that returns an IEnumerable. You can then write something like:

    foreach (Item x in Items.Subrange(10, 20)) { ... }

Partial Types

Partial types allow you to split the implementation of a class, interface
or struct into multiple separate source files. At compile-time, the compiler merges
the partial classes together and compiles the output.

The biggest benefit here is that you can have partial types that span both auto-generated
and hand-written code, and indeed this paradigm is used in the code-beside classes
in ASP.NET and Windows Forms in Whidbey. A Whidbey WinForm no longer has all the auto-generated
regions, because the code can be split out into a different class file (Form1.Designer.cs).

Other Enhancements

Static classes enable you to create classes containing only static members;
the compiler can then check that this is the case. A static class does not need to
create a private constructor to prevent instantiation. System.Console and System.Environment
are good examples of this.

Properties can now have different accessibility for get {...} and set {...}. Typically
set {...} is more restricted than get {...}.

Additional minor features include namespace aliases, pragma warnings and fixed size
buffers. These are documented in the C# 2.0 language specification.