.NET 3.5 and C# 3 New Features

Content:

  1. Version numbers
  2. Release
  3. TimeZoneInfo class
  4. HashSet class
  5. Pipes
  6. Automatic properties
  7. Extension methods
  8. Shorthands
  9. var type
  10. Lambda expressions
  11. LINQ

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 3.5, 2.0, 3 and 2008 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

Release:

.NET 3.5 and VS 2008 was released November 19th 2007.

TimeZoneInfo class

A gap in previous versions if .NET has been the poor time zone support.

.NET 3.5 has closed this gap by adding the TimeZoneInfo class.

Small example:

using System;

public class TZ
{
    public static void Main(string[] args)
    {
        // find time zone for computer (not new functionality)
        TimeZone tz = TimeZone.CurrentTimeZone;
        Console.WriteLine(tz.StandardName + " " + tz.GetUtcOffset(DateTime.Now));
        // new way to do the same in 3.5
        TimeZoneInfo tzi1 = TimeZoneInfo.Local;
        Console.WriteLine(tzi1.StandardName + " " + tzi1.GetUtcOffset(DateTime.Now));
        // find any time zone (new in 3.5)
        TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
        Console.WriteLine(tzi2.StandardName + " " + tzi2.GetUtcOffset(DateTime.Now));
    }
}

I think this is useful for certain types of applications.

I expect this to only be used by those very specific types of applications.

HashSet class

.NET 3.5 has got a new collection class HashSet that can be used for set operations.

Example showing the basic operations:

using System;
using System.Collections.Generic;
using System.Linq;

public class HS
{
    public static void Main(string[] args)
    {
        HashSet<int> hs1 = new HashSet<int>();
        hs1.Add(1);
        hs1.Add(2);
        hs1.Add(3);
        HashSet<int> hs2 = new HashSet<int>();
        hs2.Add(3);
        hs2.Add(4);
        foreach(int v in hs1) Console.Write(" " + v);
        Console.WriteLine();
        foreach(int v in hs2) Console.Write(" " + v);
        Console.WriteLine();
        // duplicates are ignored
        hs1.Add(2);
        hs1.Add(3);
        foreach(int v in hs1) Console.Write(" " + v);
        Console.WriteLine();
        // union
        HashSet<int> hs3 = new HashSet<int>(hs1.Union(hs2));
        foreach(int v in hs3) Console.Write(" " + v);
        Console.WriteLine();
        // intersecte
        HashSet<int> hs4 = new HashSet<int>(hs1.Intersect(hs2));
        foreach(int v in hs4) Console.Write(" " + v);
        Console.WriteLine();
        // complement
        HashSet<int> hs5 = new HashSet<int>(hs1.Except(hs2));
        foreach(int v in hs5) Console.Write(" " + v);
        Console.WriteLine();
    }
}

This is a very useful class in many context.

I expect this to be used.

Pipes

.NET 3.5 got support for named pipes as alternative to TCP/IP sockets.

First example of client/server using traditional TCP/IP sockets.

Server:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

public class NServer
{
    public static void Main(string[] args)
    {
        TcpListener srv = new TcpListener(IPAddress.Any, 1234);
        srv.Start();
        using(TcpClient cli = srv.AcceptTcpClient())
        {
            using(StreamReader sr = new StreamReader(cli.GetStream()))
            {
                for(int i = 0; i < 10000000; i++)
                {
                    if(sr.ReadLine() != "This is a test")
                    {
                        throw new Exception("Ooops");
                    }
                }
            }
        }
    }
}

Client:

using System;
using System.IO;
using System.Net.Sockets;

public class NClient
{
    public static void Main(string[] args)
    {
        using(TcpClient cli = new TcpClient("localhost", 1234))
        {
            using(StreamWriter sw = new StreamWriter(cli.GetStream()))
            {
                for(int i = 0; i < 10000000; i++)
                {
                    sw.WriteLine("This is a test");
                }
            }
        }
    }
}

Then the same functionality with named pipes.

Server:

using System;
using System.IO;
using System.IO.Pipes;

public class PServer
{
    public static void Main(string[] args)
    {
        using(NamedPipeServerStream pipe = new NamedPipeServerStream("test"))
        {
            pipe.WaitForConnection();
            using(StreamReader sr = new StreamReader(pipe))
            {
                for(int i = 0; i < 10000000; i++)
                {
                    if(sr.ReadLine() != "This is a test")
                    {
                        throw new Exception("Ooops");
                    }
                }
            }
        }
    }
}

Client:

using System;
using System.IO;
using System.IO.Pipes;

public class PClient
{
    public static void Main(string[] args)
    {
        using(NamedPipeClientStream pipe = new NamedPipeClientStream("test"))
        {
            pipe.Connect();
            using(StreamWriter sw = new StreamWriter(pipe))
            {
                for(int i = 0; i < 10000000; i++)
                {
                    sw.WriteLine("This is a test");
                }
            }
        }
    }
}

Whether it is best to use named pipes or TCP/IP sockets is a very complex question. There are differences in functionality, security and performance.

But does one work with client/server solutions with both client and server on the same system, then one should spend some time investigation whether named pipes would be a good fit.

I think it is a useful addition.

I expect it to see some use.

UPDATE: I was wrong - it has not been used much.

Automatic properties

C# 3 has a new shorter syntax for standard properties.

The usual way with fields and properties:

public class P
{
    private int a;
    private string b;
    public int A
    {
        get
        {
            return a;
        }
        set
        {
            a = value;
        }
    }
    public string B
    {
        get
        {
            return b;
        }
        set
        {
            b = value;
        }
    }
}

Now it can be written a lot shorter:

public class P
{
    public int A
    {
        get;
        set;
    }
    public string B
    {
        get;
        set;
    }
}

Definitely a very useful feature.

And I am 112% sure that it will become popular.

UPDATE: the de facto standard formatting has turned out to be:

public class P
{
    public int A { get; set; }
    public string B { get; set; }
}

Extension methods

C# 3 has got a feature to add methods to other classes/interfaces. The idea is a bit AOP'ish, but the implementation is very simple.

Let us start with a small example showing some formatting:

using System;

public static class MyExtensions
{
    public static string ToHexString(this int o)
    {
        return o.ToString("X");
    }
    public static string ToVmsString(this DateTime o)
    {
        return o.ToString("dd-MMM-yyyy HH:mm");
    }
}

public class Test
{
    public static void Main(string[] args)
    {
        int i = 123;
        Console.WriteLine(i.ToHexString());
        DateTime dt = DateTime.Now;
        Console.WriteLine(dt.ToVmsString());
    }
}

Note that this feature was not just added for convenience. It is also an easy way to add functionality to many existing classes, that may be outside of ones control. This can be done by defining an extension method to an interface. Then all classes implementing that interface get the method. This feature is used a lot in the .NET Framework itself for LINQ (see later), where the Enumerable<T> interface has a lot of extension methods that are applied to many classes.

I think this is a very useful feature in many situations. I will advise not to abuse it as it can be be used to create a customized/forked .NET library. And it may not always be easy to find where the extension method is defined, when it is not in the class it adds to.

I predict that this feature will be used a lot also in developers own code.

Shorthands:

C# 3 has gotten some new features to make initialization of both objects and collections less verbose.

First some traditional C# 2 code (see automatic properties section for the code for class P):

using System;
using System.Collections.Generic;

public class I20
{
    public static void Main(string[] args)
    {
        // object initialization
        P o = new P();
        o.A = 123;
        o.B = "ABC";
        Console.WriteLine(o.A + " " + o.B);
        // collection initialization
        List<int> lsti = new List<int>();
        lsti.Add(1);
        lsti.Add(2);
        lsti.Add(3);
        foreach(int v in lsti) Console.WriteLine(v);
        // combined
        List<P> lstp = new List<P>();
        P o1 = new P();
        o1.A = 123;
        o1.B = "ABC";
        lstp.Add(o1);
        P o2 = new P();
        o2.A = 456;
        o2.B = "DEF";
        lstp.Add(o2);
        foreach(P v in lstp) Console.WriteLine(v.A + " " + v.B);
    }
}

And now the same code in C# 3 version:

using System;
using System.Collections.Generic;

public class I30
{
    public static void Main(string[] args)
    {
        // object initialization
        P o = new P{A = 123, B = "ABC" };
        Console.WriteLine(o.A + " " + o.B);
        // collection initialization
        List<int> lsti = new List<int>{1, 2, 3};
        foreach(int v in lsti) Console.WriteLine(v);
        // combinedt
        List<P> lstp = new List<P>{new P{A = 123, B = "ABC" }, new P{A = 456, B = "DEF" }};
        foreach(P v in lstp) Console.WriteLine(v.A + " " + v.B);
    }
}

Note that the C# 2 code could be improved some if the P class had a constructor with arguments, but that would also add code.

Very useful feature.

And again something that I am sure will become very popular among developers.

var type

C# 3 also introduces type inference where the type of left side variable is determined by the compiler based on type of the right side expression.

Simple example:

using System;

public class V30
{
    public static void Main(string[] args)
    {
        var iv = 123;
        var sv = "ABC";
        Console.WriteLine(iv + " " + sv);
    }
}

Note that var is not equivalent with object:

using System;

public class V20
{
    public static void Main(string[] args)
    {
        object iv = 123;
        object sv = "ABC";
        Console.WriteLine(iv + " " + sv);
    }
}

is a complete different code.

The difference can be seen with:

using System;

public class V20M
{
    public static void Main(string[] args)
    {
        object iv = 123;
        object sv = "ABC";
        iv = "DEF";
        sv = 456;
        Console.WriteLine(iv + " " + sv);
    }
}

which works fine, while:

using System;

public class V30M
{
    public static void Main(string[] args)
    {
        var iv = 123;
        var sv = "ABC";
        iv = "DEF";
        sv = 456;
        Console.WriteLine(iv + " " + sv);
    }
}

Gives:

v30m.cs(9,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
v30m.cs(10,14): error CS0029: Cannot implicitly convert type 'int' to 'string'

var is type safe!

I do not consider the var type that useful for stuff like above - no C# programmer would code like that. But the vat type is essential for LINQ (see later) and anonymous types.

I expect the feature to be used a lot with LINQ and anonymous types.

UPDATE: I was wrong - many C# developers are using it for all sorts of types to avoid explcit specifying the type name - like in Scala. I don't understand it, but it is reality.

Lambda expressions:

Lambda expressions is a very hyped feature in C# 3.

And it is well aligned with the overall C# direction.

Let us start with a C# 1 example:

using System;

public class Solv
{
    // Newtons formula for iterative equation solving 
    private const double DELTA = 0.0000001;
    public delegate double FX(double x);
    public static double FindZero(FX f)
    {
        double x, xnext = 0;
        do
        {
            x = xnext;
            xnext = x - f(x) / ((f(x + DELTA) - f(x)) / DELTA);
        } while(Math.Abs(xnext - x) > DELTA);
        return xnext;
    }
    // simple third degree polynomium y=x^3+x-30 with a single solution x=3
    public static double MyPoly(double x)
    {
        return x * x * x + x - 30; 
    }
    // solve
    public static void Main(string[] args)
    {
        Console.WriteLine(Solv.FindZero(MyPoly));
    }
}

In C# 2 with anonymous method:

using System;

public class Solv
{
    // Newtons formula for iterative equation solving  
    private const double DELTA = 0.0000001;
    public delegate double FX(double x);
    public static double FindZero(FX f)
    {
        double x, xnext = 0;
        do
        {
            x = xnext;
            xnext = x - f(x) / ((f(x + DELTA) - f(x)) / DELTA);
        } while(Math.Abs(xnext - x) > DELTA);
        return xnext;
    }
    // solve simple third degree polynomium y=x^3+x-30 with a single solution x=3
    public static void Main(string[] args)
    {
        Console.WriteLine(Solv.FindZero(delegate(double x) { return x * x * x + x - 30; }));
    }
}

And now C# 3 with lambda expression:

using System;

public class Solv
{
    // Newtons formula for iterative equation solving  
    private const double DELTA = 0.0000001;
    public delegate double FX(double x);
    public static double FindZero(FX f)
    {
        double x, xnext = 0;
        do
        {
            x = xnext;
            xnext = x - f(x) / ((f(x + DELTA) - f(x)) / DELTA);
        } while(Math.Abs(xnext - x) > DELTA);
        return xnext;
    }
    // solve simple third degree polynomium y=x^3+x-30 with a single solution x=3
    public static void Main(string[] args)
    {
        Console.WriteLine(Solv.FindZero((double x) => x * x * x + x - 30 ));
    }
}

Definitely nicer syntax. But I do not see its importance match the hype.

I am sure that developers will use this feature.

LINQ:

No feature in C# 3 has been hyped like LINQ.

LINQ = Language INtegrated Query

The short explanation: the ability to use SQL like syntax directly in C# code.

LINQ is a very big topic so this text will only introduce a few basic possibilities.

First LINQ for Objects.

Example (again reusing the P class from above and utilizing several of the above discussed new features):

using System;
using System.Linq;
using System.Collections.Generic;

public class LINQforObjects
{
    public static void Main(string[] args)
    {
        List<P> lstp = new List<P>{new P{A = 123, B = "ABC" }, new P{A = 456, B = "DEF" }};
        // select one object (returning IEnumrable<P>)
        var q1 = from o in lstp where o.A == 123 select o;
        foreach(var o in q1) Console.WriteLine(o.A + " " + o.B);
        // select single property from single object (returning IEnumrable<string>)
        var q2 = from o in lstp where o.A == 123 select o.B;
        foreach(var o in q2) Console.WriteLine(o);
        // select parts of objects (returning IEnumrable<> of anonymous type)
        var q3 = from o in lstp where o.A == 123 select new { o.A, o.B};
        foreach(var o in q3) Console.WriteLine(o.A + " " + o.B);
        // select aggregate function to single value (returning type decimal)
        var q4 = (from o in lstp select o.A).Average();
        Console.WriteLine(q4);
    }
}

Note that this code could also be made more traditional with lambda expressions:

using System;
using System.Linq;
using System.Collections.Generic;

public class LINQforObjects
{
    public static void Main(string[] args)
    {
        List<P> lstp = new List<P>{new P{A = 123, B = "ABC" }, new P{A = 456, B = "DEF" }};
        // select objects (returning IEnumerable<P>)
        var q1 = lstp.Where(o => o.A == 123).Select(o => o);
        foreach(var o in q1) Console.WriteLine(o.A + " " + o.B);
        // select single property from objects (returning IEnumerable<string>)
        var q2 = lstp.Where(o => o.A == 123).Select(o => o.B);
        foreach(var o in q2) Console.WriteLine(o);
        // select properties of objects (returning IEnumerable<> of anonymous type)
        var q3 = lstp.Where(o => o.A == 123).Select( o => new { o.A, o.B});
        foreach(var o in q3) Console.WriteLine(o.A + " " + o.B);
        // select aggregate function to single value (returning type decimal)
        var q4 = lstp.Select(o => o.A).Average();
        Console.WriteLine(q4);
    }
}

And now LINQ for SQL.

Example will use a test database table created with:

CREATE TABLE T1 (F1 INTEGER NOT NULL PRIMARY KEY, F2 VARCHAR(50))
GO
INSERT INTO T1 VALUES(1, 'A')
GO
INSERT INTO T1 VALUES(2, 'BB')
GO
INSERT INTO T1 VALUES(3, 'CCC')
GO

Now the same code as before just with database instead of collection:

using System;
using System.Linq;
using System.Data.Linq;
using System.Data.Linq.SqlClient;
using System.Data.Linq.Mapping;
using System.Data.SqlClient;

public class LINQforDatabase
{
    [Table(Name="T1")]
    public class T1
    {
        [Column(IsPrimaryKey=true)]
        public int F1;
        [Column]
        public string F2;
    }
    public static void Main(string[] args)
    {
        SqlConnection con = new SqlConnection(@"Server=ARNEPC3\SQLEXPRESS;Integrated Security=SSPI;Database=Test");
        DataContext db = new DataContext(con);
        Table<T1> t1 = db.GetTable<T1>();
        // select rows (returning IEnumerable<T1>)
        var q1 = from r in t1 where r.F1 == 2 select r; 
        foreach(var r in q1) Console.WriteLine(r.F1 + " " + r.F2);
        // select single column from rows (returning IEnumerable<string>)
        var q2 = from r in t1 where r.F1 == 2 select r.F2;
        foreach(var r in q2) Console.WriteLine(r);
        // select columns of rows (returning IEnumerable<> of anonymous type)
        var q3 = from r in t1 where r.F1 == 2 select new { r.F1, r.F2};
        foreach(var r in q3) Console.WriteLine(r.F1 + " " + r.F2);
        // select aggregate function to single value (returning type decimal)
        var q4 = (from r in t1 select r.F1).Average();
        Console.WriteLine(q4);
        con.Close();
    }
}

There is a lot more to say about this topic.

Reading about it could start at http://msdn2.microsoft.com/en-us/library/bb425822.aspx.

LINQ for XML.

It is also possible to work with XML documents using LINQ. Instead of the traditional XmlDocument class, then one use the XDocument class and can extract data with LINQ similar to how it can be done with XPath.

UPDATE: .NET 3.5 SP1 was released August 11th 2008 and introduced an ORM for .NET called Entity Framework (usually abbreviated EF). And it also introduced LINQ for Entities that sort of replaced LINQ for SQL.

LINQ is certainly a revolutionary innovation.

I am not convinced that it will be used as much as the innovation (and the hype) indicate. Most of this stuff was not really difficult to do before.

UPDATE: the reality is a bit mixed. The real LINQ embedded DSL is not used much. Very few want to spend time learning a new language that makes the code more verbose and less readable. But the C# syntax with IEnumerable<T> extension methods and lambda expressions is highly used all over. It is very easy and convenient to use its fluent interface. LINQ for Objects is used a lot. LINQ for EF is used a lot. LINQ for XML is used some. LINQ for NHibernate is used some.

Next:

See .NET 4.0 and C# 4 New Features.

Article history:

Version Date Description
1.0 November 22nd 2007 Initial version (in Danish) published on Eksperten.dk
1.1 December 26th 2008 Minor changes
1.2 February 14th 2010 Minor changes
2.0 July 31st 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