.NET 4.0 and C# 4 New Features

Content:

  1. Version numbers
  2. Release
  3. Optional parameters
  4. Named parameters
  5. dynamic & DLR
  6. Covariance and Contravariance
  7. Parallel extensions
  8. POCO
  9. Contracts

Version numbers:

.NET framework, .NET runtime, C# language/compiler and Visual Studio IDE each have their own version numbering scheme. For this release they are at 4.0, 4.0, 4 and 2010 respectively.

.NET framework .NET runtime C# language/compiler Visual Studio IDE Release date
1.0 1.0 1.0 2002 February 13th 2002
1.1 1.1 1.2 2003 April 24th 2003
2.0 2.0 2.0 2005 November 7th 2005
3.5 2.0 3.0 2008 November 19th 2007
4.0 4.0 4.0 2010 April 12th 2010

Release:

.NET 4.0 and VS 2010 was released April 12th 2010.

Optional parameters:

It is now possible to specify a default value for parameters and thereby making it optional to specify them - similar to C++ and other languages.

Syntax: typename parametername = default

Previously it was necesarry to:

using System;

public class DefParm
{
    private int v;
    public DefParm() : this(0)
    {
    }
    public DefParm(int v)
    {
        this.v = v;
    }
    public override string ToString() 
    {
        return "v:" + v;
    }
    public static void Main(string[] args) 
    {
        Console.WriteLine(new DefParm());
        Console.WriteLine(new DefParm(1));
    }
}

Now it is possible to:

using System;

public class DefParm
{
    private int v;
    public DefParm(int v = 0)
    {
        this.v = v;
    }
    public override string ToString() 
    {
        return "v:" + v;
    }
    public static void Main(string[] args) 
    {
        Console.WriteLine(new DefParm());
        Console.WriteLine(new DefParm(1));
    }
}

It can obviously be used in all methods not just constructors.

I consider this to be a very practical little feature.

I predict that it will be used as soon as developers notice it.

UPDATE: That prediction turned out to be wrong. This feature is rarely used.

Named parameters:

To get full benefit from optional parameters then named parameters has also been added.

Syntax: parametername : value

Previously it was necesarry to:

using System;

public class NamParm
{
    private int v1;
    private int v2;
    private int v3;
    public NamParm() : this(0, 0, 0)
    {
    }
    public NamParm(int v1, int v2, int v3)
    {
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;
    }
    public override string ToString() 
    {
        return "v1:" + v1 + " v2:" +v2 + " v3:" + v3;
    }
    public static void Main(string[] args) 
    {
        Console.WriteLine(new NamParm());
        Console.WriteLine(new NamParm(0, 1, 0));
    }
}

Now it is possible to:

using System;

public class NamParm
{
    private int v1;
    private int v2;
    private int v3;
    public NamParm(int v1 = 0, int v2 = 0, int v3 = 0)
    {
        this.v1 = v1;
        this.v2 = v2;
        this.v3 = v3;
    }
    public override string ToString() 
    {
        return "v1:" + v1 + " v2:" +v2 + " v3:" + v3;
    }
    public static void Main(string[] args) 
    {
        Console.WriteLine(new NamParm());
        Console.WriteLine(new NamParm(v2:1));
    }
}

I consider this to be a very practical little feature.

I predict that it will be used as soon as developers notice it.

UPDATE: That prediction turned out to be wrong. This feature is rarely used.

dynamic & DLR:

C# got a new type dynamic that can be anything.

To illustrate how it is different from object and var we will look at some code examples.

First normal code:

using System;

public class Std
{
    public static void Main(String[] args) 
    {
        int o1 = 123;
        string o2 = "ABC";
        o1 = 123.456; // not allowed to ref to another type
        string s1x = o1.Substring(1); // not allowed to use methods not in actual type
        string s2x = o2.Substring(1); // allowed to use methods in actual type
    }
}

Object can point to anything, but one can only use the methods in object:

using System;

public class Obj
{
    public static void Main(String[] args) 
    {
        object o1 = 123;
        object o2 = "ABC";
        o1 = 123.456; // allowed to ref to another type
        string s1x = o1.Substring(1); // not allowed to use methods not in object
        string s2x = o2.Substring(1); // not allowed to use methods not in object
    }
}

C# 3 introduced the new var "type", but it really works completely like the normal code - the actual type is just inferred. from right side expression by the compiler instead of the developer explcit specifying it:

using System;

public class Var
{
    public static void Main(String[] args) 
    {
        var o1 = 123;
        var o2 = "ABC";
        o1 = 123.456; // not allowed to ref to another type
        string s1x = o1.Substring(1); // not allowed to use methods not in actual type
        string s2x = o2.Substring(1); // allowed to use methods in actual type
    }
}

Note that saving the developer to explicit specify the type is not the only reason for introducing var. The var "type" can also be used for anonymous types that do not have a name, so the developer can not specify a name:

using System;

public class WhyVar
{
    public static void Main(String[] args) 
    {
        var z = new { A=123, B="ABC" };
        Console.WriteLine(z.A + " " + z.B);
    }
}

And finally C# 4 and dynamic. The type dynamic can point to anything and all members (fields/properties/methods) can be used - the compiler do not check - instead a check at runtime is performed. This is similar to variables in script languages like PHP:

using System;

public class Dyn
{
    public static void Main(String[] args) 
    {
        dynamic o1 = 123;
        dynamic o2 = "ABC";
        o1 = 123.456; // allowed to ref to another type
        string s1x = o1.Substring(1); // allowed to use methods not in actual type (but will generate runtime execption !)
        string s2x = o2.Substring(1); // allowed to use methods in actual type
    }
}

I consider this to be a less important feature. Only relevant area would be COM interop. But the infrastructure behind it - DLR (Dynamic Language Runtime) - is very useful for implementing dynamic typed languages on the .NET platform.

I predict that it will not be used much.

Covariance and Contravariance:

C# 4 allows covariance and contravariance for generic interfaces and delegates, if they declare to fulfill contract and do so in exposed methods.

That is a lot easier to understand via some examples. The examples are a bit long, but it is complex to illustrate these things.

First covariance.

Here is some C# 3 code that does not work:

using System;

public class P
{
    public void M()
    {
        Console.WriteLine("M here");
    }
}

public class C : P
{
}

public interface IFoobar<T>
{
    T GetOne();
}

public class Foobar<T> : IFoobar<T> where T : new()
{
    public T GetOne()
    {
        return new T();
    }
}

public class Program
{
    public static void Main(String[] args) 
    {
       IFoobar<P> fb = new Foobar<C>(); // compile error
       IFoobar<P> fb = (IFoobar<P>)new Foobar<C>(); // runtime error
       P o = fb.GetOne();
       o.M();
    }
}

It is not possible to make that assignment. For good reasons - consider the scenario where IFoobar had a method that expected a T as input like:

public void PutOne(T o);

Then new Foobar<C> and call PutOne with a sub class of P other than C would break all type safety.

But now C# 4 has a solution:

using System;

public class P
{
    public void M()
    {
        Console.WriteLine("M here");
    }
}

public class C : P
{
}

public interface IFoobar<out T>
{
    T GetOne();
}

public class Foobar<T> : IFoobar<T> where T : new()
{
    public T GetOne()
    {
        return new T();
    }
}

public class Program
{
    public static void Main(String[] args) 
    {
       IFoobar<P> fb = new Foobar<C>();
       P o = fb.GetOne();
       o.M();
    }
}

This works because:

Similar/reverse with contravariance.

C# 3:

using System;

public class P
{
    public void M()
    {
        Console.WriteLine("M here");
    }
}

public class C : P
{
}

public interface IFoobar<T> where T : P
{
    void CallM(T o);
}

public class Foobar<T> : IFoobar<T> where T : P
{
    public void CallM(T o)
    {
        o.M();
    }
}

public class Program
{
    public static void Main(String[] args) 
    {
       IFoobar<C> fb = new Foobar<P>(); // compile error
       IFoobar<C> fb = (IFoobar<C>)new Foobar<P>(); // runtime error
       fb.CallM(new C());
    }
}

does not work.

C# 4:

using System;

public class P
{
    public void M()
    {
        Console.WriteLine("M here");
    }
}

public class C : P
{
}

public interface IFoobar<in T> where T : P
{
    void CallM(T o);
}

public class Foobar<T> : IFoobar<T> where T : P
{
    public void CallM(T o)
    {
        o.M();
    }
}

public class Program
{
    public static void Main(String[] args) 
    {
       IFoobar<C> fb = new Foobar<P>();
       fb.CallM(new C());
    }
}

works because:

I consider this to be a very useful feature when needed.

I predict that it will not be used much as it is too rarely needed and too complex to understand.

Parallel extensions:

.NET 4.0 comes with a new parallel task library that makes it easier to write multi-threaded programs.

The concept is very simple. The developer tell that something should be parallelized and .NET determines how many threads to use and handle all the practical about starting threads and waiting for thread completion.

Very similar to the parallel programming features that has been used in Fortran for vector and matrix calculations for 20 years.

First an example with for and foreach loops.

Traditional serialized code:

using System;

public class MainClass
{
    public static void Main(string[] args)
    {
        int[] a = new int[1000];
        int[] b = new int[1000];
        for(int i = 0; i < a.Length; i++)
        {
            a[i] = i;
        }
        for(int i = 0; i < b.Length; i++)
        {
            b[i] = a[i] + 1;
        }
        foreach(int bv in b)
        {
            if(bv <= 0) throw new Exception("Ooops");
        }
        Console.WriteLine(b[77]);
    }
}

Same logic with .NET 4.0 parallel:

using System;
using System.Threading.Tasks;

public class MainClass
{
    public static void Main(string[] args)
    {
        int[] a = new int[1000];
        int[] b = new int[1000];
        Parallel.For(0, a.Length, (i) => { a[i] = i; } );
        Parallel.For(0, b.Length, (i) => { b[i] = a[i] + 1; } );
        Parallel.ForEach(b, (bv) => { if(bv <= 0) throw new Exception("Ooops"); } );
        Console.WriteLine(b[77]);
    }
}

Now a more general example of code to be executed in parallel.

Traditional code explicit managing threads:

using System;
using System.Threading;

public class MainClass
{
    public static void Main(string[] args)
    {
        Thread t1 = new Thread(Run1);
        Thread t2 = new Thread(Run2);
        Thread t3 = new Thread(Run3);
        t1.Start();
        t2.Start();
        t3.Start();
        t1.Join();
        t2.Join();
        t3.Join();
    }
    public static void Run1()
    {
        Console.WriteLine("Run1 in " + Thread.CurrentThread.ManagedThreadId);
    }
    public static void Run2()
    {
        Console.WriteLine("Run2 in " + Thread.CurrentThread.ManagedThreadId);
    }
    public static void Run3()
    {
        Console.WriteLine("Run3 in " + Thread.CurrentThread.ManagedThreadId);
    }
}

Same logic with .NET 4.0 parallel:

using System;
using System.Threading;
using System.Threading.Tasks;

public class MainClass
{
    public static void Main(string[] args)
    {
        // first way
        Parallel.Invoke(Run1, Run2, Run3);
        // second way
        Task t1 = new Task(Run1);
        Task t2 = new Task(Run2);
        Task t3 = new Task(Run3);
        t1.Start();
        t2.Start();
        t3.Start();
        Task.WaitAll(t1, t2, t3);
    }
    public static void Run1()
    {
        Console.WriteLine("Run1 in " + Thread.CurrentThread.ManagedThreadId);
    }
    public static void Run2()
    {
        Console.WriteLine("Run2 in " + Thread.CurrentThread.ManagedThreadId);
    }
    public static void Run3()
    {
        Console.WriteLine("Run3 in " + Thread.CurrentThread.ManagedThreadId);
    }
}

And if someone wonder why to use Task instead of Parallel.Invoke, then Task provides several extra capabilities.

Parallel extensions are also added to LINQ, so that LINQ can be executed multi-threaded.

Tradionel LINQ:

using System;
using System.Linq;
using System.Threading;

public class MainClass
{
    public static void Main(string[] args)
    {
        int[] a = new int[] { 1, 4, 9, 25, 36, 49, 64, 81, 100 };
        int maxa = a.Max();
        Console.WriteLine(maxa);
        // same but with debug to see how it is actually done
        int xmaxa = a.Max((v) => X(v));
        Console.WriteLine(xmaxa);
    }
    public static int X(int v)
    {
        Console.WriteLine("checking " + v + " in " + Thread.CurrentThread.ManagedThreadId);
        return v;
    }
}

Parallel LINQ (also known as PLINQ):

using System;
using System.Linq;
using System.Threading;

public class MainClass
{
    public static void Main(string[] args)
    {
        int[] a = new int[] { 1, 4, 9, 25, 36, 49, 64, 81, 100 };
        int maxa = a.AsParallel().Max();
        Console.WriteLine(maxa);
        // same but with debug to see how it is actually done
        int xmaxa = a.AsParallel().Max((v) => X(v));
        Console.WriteLine(xmaxa);
    }
    public static int X(int v)
    {
        Console.WriteLine("checking " + v + " in " + Thread.CurrentThread.ManagedThreadId);
        return v;
    }
}

I consider this to be a very useful feature as multi-threaded code often is cumbersome to write and get right - and with 4/6/8/10 core CPU's then multi-threaded programming is a must.

I predict that it will be used a lot when as developers discover it and get used to it.

UPDATE: That prediction turned out to be wrong. This feature is rarely used.

POCO:

.NET 3.5 SP1 added an ORM to the .NET framework called EF (Entity Framework).

But in the first version the classes should extend System.Data.Objects.DataClasses.EntityObject.

With .NET 4.0 it is possible to use EF with POCO's (Plain Old Clr Object's).

Contracts:

.NET 4.0 comes with some exciting new support for code contracts.

First let us see some code:

using System;
using System.Diagnostics.Contracts;

public class Test
{
    private int v = 0;
    [ContractInvariantMethod]
    protected void ObjectInvariant()
    {
        Contract.Invariant(v < 100);
    }
    public void M1()
    {
        Contract.Requires(1 <= v && v <= 10);
        Console.WriteLine(v);
    }
    public void M2()
    {
        Contract.Ensures(1 <= v && v <= 10);
        Console.WriteLine(v);
    }
    public void M3()
    {
        Contract.EnsuresOnThrow<Exception>(1 <= v && v <= 10);
        throw new Exception("Ooops");
    }
    public void M4()
    {
        v = 200;
        Console.WriteLine(v);
    }
}

public class Program
{
    public static void Main(String[] args) 
    {
        Test o = new Test();
        o.M1(); // violates pre condition
        o.M2(); // violates post condition
        o.M3(); // violates post condition
        o.M4(); // violates invariant
    }
}

Note that this is completely different from traditional if something then throw new exceptions, various asserts etc..

Traditional tests:

Contracts:

Both static code analysis and build with runtime checks can be done via Visual Studio.

Contracts are really a form of AOP (Aspect Oriented Programming).

I doubt that this feature has found its final form, but it looks very interesting. Unfortunatetly I doubt that it will be used much. It is too advanced for ordinary software development.

Next:

See .NET 4.5 and C# 5 New Features.

Article history:

Version Date Description
1.0 November 11th 2009 Initial version (in Danish) published on Eksperten.dk
1.1 February 12th 2010 Minor changes
2.0 July 30th 2016 Translation to English and complete reformatting and publishing here
2.1 October 8th 2016 Add content overview
2.2 March 23rd 2017 Add release dates

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj