.NET 4.6 and C# 6 New Features

Content:

  1. Version numbers
  2. Release
  3. General
  4. Enhancements auto properties
  5. null operator
  6. nameof operator
  7. Index initalizers
  8. using static
  9. String formatting
  10. catch when
  11. Other

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.6, 4.0, 6.0 and 2015 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
4.5 4.0 5.0 2012 August 15th 2012
4.5.1 4.0 5.0 2013 October 17th 2013
4.6 4.0 6.0 2015 July 20th 2015

Release:

.NET 4.6 and VS 2015 was released July 20th 2015.

General:

The changes to .NET are minor (except for ASP.NET), but the changes to C# are major.

The changes to C# are not a few revolutionary changes but many small changes that increases usability significantly. It seems like MS wanted to get some of the enhancements that had been on the TODO list for some time done with this release.

Enhancements auto properties:

It is now possible to use initializers on properties just like for fields.

Syntax: visibility type name { get; set; } = value ;

Previously it was necesarry to:

using System;

namespace E
{
    public class Data
    {
        public int A { get; set; }
        public int B { get; set; }
        public Data() 
        {
            A = 123;
            B = 456;
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Data o = new Data();
            Console.WriteLine(o.A + " " + o.B);
        }
    }
}

Now it is possible to:

using System;

namespace E
{
    public class Data
    {
        public int A { get; set; } = 123;
        public int B { get; set; } = 456;
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Data o = new Data();
            Console.WriteLine(o.A + " " + o.B);
        }
    }
}

This makes it possible to have readonly (only get) auto properties.

Syntax: visibility type name { get; } = value ;

Previously it was necesarry to:

using System;

namespace E
{
    public class Data
    {
        public int A { get; set; }
        private int _b;
        public int B { get { return _b; } }
        public Data() 
        {
            A = 123;
            _b = 456;
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Data o = new Data();
            Console.WriteLine(o.A + " " + o.B);
        }
    }
}

Now it is possible to:

using System;

namespace E
{
    public class Data
    {
        public int A { get; set; } = 123;
        public int B { get; } = 456;
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Data o = new Data();
            Console.WriteLine(o.A + " " + o.B);
        }
    }
}

I consider these to be less important but still very practical features.

I predict that these will be used as developers start getting used to them.

null operator:

A new null operator make it easy to test for a reference being null before using a member and return null if the reference is null.

Syntax: object reference ? . member

Previously it was necesarry to:

using System;

namespace E
{
    public class Program
    {
        public static void Dump(object o)
        {
            string s = (o != null) ? o.ToString() : null;
            Console.WriteLine((s == null) + " : " + s);
        }
        public static void Main(string[] args)
        {
            Dump("ABC");
            Dump(null);
        }
    }
}

Now it is possible to:

using System;

namespace E
{
    public class Program
    {
        public static void Dump(object o)
        {
            string s = o?.ToString();
            Console.WriteLine((s == null) + " : " + s);
        }
        public static void Main(string[] args)
        {
            Dump("ABC");
            Dump(null);
        }
    }
}

I consider this to be less important but still a very practical feature.

I predict that this will be used as developers start getting used to it.

nameof operator:

A new nameof operator returns the name of the variable as string.

Syntax: nameof ( variable )

It is equivalent to the #variable constuct in C/C++ macros.

Example:

using System;

namespace E
{
    public class Program
    {
        public static void Dump(string s)
        {
            Console.WriteLine(nameof(s) + " = " + s);
        }
        public static void Main(string[] args)
        {
            String sv = "ABC";
            Console.WriteLine(nameof(sv) + " = " + sv);
            Dump(sv);
        }
    }
}
Output:
sv = ABC
s = ABC

I consider this to be less important feature.

I predict that this will not be used much.

Index initalizers:

It is now easy to initialize indexable types including Dictionary.

Syntax: type name = new type ( ) = { [index] = value, ..., [index] = value };

Previously it was necesarry to:

using System;
using System.Collections.Generic;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic[1] = "A";
            dic[2] = "BB";
            dic[3] = "CCC";
            foreach(KeyValuePair<int, string> kvp in dic)
            {
                Console.WriteLine(kvp.Key + " -> " + kvp.Value);
            }
        }
    }
}

Now it is possible to:

using System;
using System.Collections.Generic;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Dictionary<int, string> dic = new Dictionary<int, string>() {[1] = "A",[2] = "BB",[3] = "CCC" };
            foreach(KeyValuePair<int, string> kvp in dic)
            {
                Console.WriteLine(kvp.Key + " -> " + kvp.Value);
            }
        }
    }
}

But it is actually not that much different for Dictionary, because previously an alternative did exist:

using System;
using System.Collections.Generic;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Dictionary<int, string> dic = new Dictionary<int, string>() { {1,"A"}, {2,"BB"}, {3,"CCC"} };
            foreach(KeyValuePair<int, string> kvp in dic)
            {
                Console.WriteLine(kvp.Key + " -> " + kvp.Value);
            }
        }
    }
}

What is really new is that it can be used for a custom indexable type:

using System;

namespace E
{
    public enum MyIndex { ONE, TWO, THREE }
    public class MyIntArray
    {
        private int[] data = new int[Enum.GetValues(typeof(MyIndex)).Length];
        private int RealIndex(MyIndex ix)
        {
            return (int)ix - (int)Enum.GetValues(typeof(MyIndex)).GetValue(0);
        }
        public int this[MyIndex ix]
        {
            get { return data[RealIndex(ix)]; }
            set { data[RealIndex(ix)] = value; }
        }


    }
    public class Program
    {
        public static void Main(string[] args)
        {
            MyIntArray mia = new MyIntArray() {[MyIndex.ONE] = 123,[MyIndex.TWO] = 456,[MyIndex.THREE] = 789 };
            Console.WriteLine(mia[MyIndex.TWO]);
        }
    }
}

I consider this to be less important feature.

I predict that this will not be used much. It is very useful if it is needed, but it will only be needed in very few cases.

using static:

It is now possible to import the static members of a class.

Syntax: using static namespace . class ;

Previously it was necesarry to:

using System;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            double x = Math.PI / 2;
            Console.WriteLine(x);
            double x2 = Math.Acos(Math.Cos(x));
            Console.WriteLine(x2);
        }
    }
}

Now it is possible to:

using System;
using static System.Math;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            double x = PI / 2;
            Console.WriteLine(x);
            double x2 = Acos(Cos(x));
            Console.WriteLine(x2);
        }
    }
}

This is equivalent with Java import static feature added to Java 1.5 in 2004. And it is really only useful in very rare cases like Math. But in .NET it actually have an additional usage that is very relevant. It is possible to just import extendsion methods from one class instead of an entire namespace.

Example:

using System;

namespace X
{
    public static class MyExtensionsOne
    {
        public static void A(this int v)
        {
            Console.WriteLine("A: " + v);
        }
    }
    public static class MyExtensionsTwo
    {
        public static void B(this int v)
        {
            Console.WriteLine("B: " + v);
        }
    }
}

namespace Y
{
    public static class MyExtensionsThree
    {
        public static void C(this int v)
        {
            Console.WriteLine("C: " + v);
        }
    }
    public static class MyExtensionsFour
    {
        public static void D(this int v)
        {
            Console.WriteLine("D: " + v);
        }
    }
}

namespace E
{
    using X;
    using static Y.MyExtensionsThree;
    public class Program
    {
        public static void Main(string[] args)
        {
            int v = 123;
            v.A();
            v.B();
            v.C();
            /*
            Does not compile:
            v.D();
            */
        }
    }
}

I consider this to be great feature. Not because it can be used with Math, but because it can limit the scope of extension method imports. In my opinion import of extension maethods by namespace is way to coarse.

I predict that this will not be used much. Math heavy code is rare and very few care about the import of extension methods..

String formatting:

It is now possible to use put variables directly into a string.

Just prefix "" with $ and put variables in curly brackets.

Previously it was necesarry to:

using System;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            int iv = 123;
            string sv = "ABC";
            string s = string.Format("{0} {1}", iv, sv);
            Console.WriteLine(s);
        }
    }
}

Now it is possible to:

using System;

namespace StringFormatting6
{
    public class Program
    {
        public static void Main(string[] args)
        {
            int iv = 123;
            string sv = "ABC";
            string s = $"{iv} {sv}";
            Console.WriteLine(s);
        }
    }
}

This is equivalent with PHP functionality: $s = "$iv $sv";.

I consider this to be a less important but still very practical feature.

I predict that this will be used as developers start getting used to it.

catch when:

It is now possible to put a condition on a catch clause.

Syntax: catch ( exceptiontype name ) where ( condition ).

Previously it was necesarry to:

using System;

namespace E
{
    public class Program
    {
        public static void DoSomething()
        {
            throw new Exception("This is not really an exception");
        }
        public static void TryThreeTimes()
        {
            int ntry = 0;
            while(true)
            {
                ntry++;
                try
                {
                    DoSomething();
                    break;
                }
                catch (Exception ex)
                {
                    if(ntry < 3)
                    {
                        Console.WriteLine("Retrying: " + ex.Message);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
        public static void Main(string[] args)
        {
            try
            {
                TryThreeTimes();
            }
            catch(Exception ex)
            {
                Console.WriteLine("Giving up on: " + ex.Message);
            }
        }
    }
}

Now it is possible to:

using System;

namespace E
{
    public class Program
    {
        public static void DoSomething()
        {
            throw new Exception("This is not really an exception");
        }
        public static void TryThreeTimes()
        {
            int ntry = 0;
            while(true)
            {
                ntry++;
                try
                {
                    DoSomething();
                    break;
                }
                catch (Exception ex) when(ntry < 3)
                {
                    Console.WriteLine("Retrying: " + ex.Message);
                }
            }
        }
        public static void Main(string[] args)
        {
            try
            {
                TryThreeTimes();
            }
            catch(Exception ex)
            {
                Console.WriteLine("Giving up on: " + ex.Message);
            }
        }
    }
}

I consider this to be a less important feature.

I predict that this will be used very rarely as there will not be much need for it.

Other:

This release contains a new compiler platform commonly known by its codename Roslyn.

This release contains a new more efficient JIT compiler for 64 bit platform commonly known by its codename RyuJIT.

Note that the initial release of RyuJIT had a subtle bug. See here for more details:

Article history:

Version Date Description
1.0 September 13th 2015 Initial version
1.1 July 14th 2016 Minor edits
1.2 October 8th 2016 Add content overview
1.3 March 23rd 2017 Add release dates

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj