.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.5, 4.0, 5.0 and 2012 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 |
.NET 4.5 and VS 2012 was released August 15th 2012.
This update is different than previous updates.
In some ways this is the biggest update ever in .NET and C#. In other ways it is only minor updates.
First an important note.
A system with only .NET 4.0 runtime (Windows 8 or 2012 out of the box) will per default not run .NET 2.0 and 3.5 applications.
Either .NET 3.5 must be installed (which will be suggested) or something must be added to app.config:
<configuration>
<startup>
<supportedRuntime version="v2.0.50727" />
<supportedRuntime version="v4.0" />
</startup>
</configuration>
or:
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
</startup>
</configuration>
The last one should be good for COM and/or mixed mode C++ - I do not have the details.
Previously max size for objects was 2 GB.
It can not be increased in app.config for .NET 4.5 for 64 bit Windows:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
Note that:
By far the biggest change in C# 5.0 is the introduction of async and await.
And even though the idea in asynchroneous calls is simple, then these two keywords can be tricky to understand.
And it does not help that the choice of keywords are a bit misleading.
async does not make calls to the method asynchroneous - it just makes it possible to use await in the method.
await does not wait - instead it makes the execution asynchroneous.
So to make an asynchroneous call then one need to:
The C# compiler will then generate code where the awaited code will be executed in another thread while the method returns immediatetly.
Let us see some examples.
Normal synchroneous version:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy1
{
public class Program
{
public static void Test()
{
Thread.Sleep(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
}
public static void Main(string[] args)
{
Test();
Test();
Test();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
Output looks like expected:
Thread 1 done at 11:31:36.757 Thread 1 done at 11:31:37.769 Thread 1 done at 11:31:38.769 Calls completed at 11:31:38.769 Main done at 11:31:41.869
Now with async and await:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy2
{
public class Program
{
public async static Task Test()
{
await Task.Delay(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
}
public static void Main(string[] args)
{
Test();
Test();
Test();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
Output now looks like:
Calls completed at 11:37:03.154 Thread 4 done at 11:37:04.157 Thread 6 done at 11:37:04.178 Thread 5 done at 11:37:04.178 Main done at 11:37:06.265
Where we see that:
We also note that:
Sometimes it is necesarry to wait for something executing asynchroneously to complete. That can be done via the returned Task object:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy3
{
public class Program
{
public async static Task Test()
{
await Task.Delay(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
}
public static void Main(string[] args)
{
Task t1 = Test();
t1.Wait();
Task t2 = Test();
t2.Wait();
Task t3 = Test();
t3.Wait();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
Now output looks like:
Thread 4 done at 11:42:08.110 Thread 4 done at 11:42:09.123 Thread 4 done at 11:42:10.137 Calls completed at 11:42:10.137 Main done at 11:42:13.237
But note that usually a lot of code will be executed between await return and Wait.
Task is also important when one need a value returned.
First attempt:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy4
{
public class Program
{
public async static Task<int> Test()
{
await Task.Delay(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
return 123;
}
public static void Main(string[] args)
{
int v1 = Test().Result;
int v2 = Test().Result;
int v3 = Test().Result;
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Console.WriteLine("{0} {1} {2}", v1, v2, v3);
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
gives:
Thread 4 done at 11:45:19.336 Thread 4 done at 11:45:20.351 Thread 4 done at 11:45:21.363 Calls completed at 11:45:21.363 123 123 123 Main done at 11:45:24.463
Result does a Wait.
So:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy5
{
public class Program
{
public async static Task<int> Test()
{
await Task.Delay(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
return 123;
}
public static void Main(string[] args)
{
Task<int> t1 = Test();
Task<int> t2 = Test();
Task<int> t3 = Test();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
int v1 = t1.Result;
int v2 = t2.Result;
int v3 = t3.Result;
Console.WriteLine("{0} {1} {2}", v1, v2, v3);
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
which does the desired:
Calls completed at 11:47:13.962 Thread 4 done at 11:47:14.963 Thread 5 done at 11:47:14.964 Thread 6 done at 11:47:14.964 123 123 123 Main done at 11:47:18.064
To illustrate what happens behind the scene then we now do the same without async and awit:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy6
{
public class Program
{
public static Task Test()
{
return Task.Run( () => {
Thread.Sleep(1000);
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
});
}
public static void Main(string[] args)
{
Test();
Test();
Test();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
and:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Asy7
{
public class Program
{
public static Task Test()
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
Timer t = new Timer(cb => {
Console.WriteLine("Thread {0} done at {1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"));
tcs.SetResult("not used");
});
t.Change(1000, -1);
return tcs.Task;
}
public static void Main(string[] args)
{
Test();
Test();
Test();
Console.WriteLine("Calls completed at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
Thread.Sleep(3100);
Console.WriteLine("Main done at {0}", DateTime.Now.ToString("HH:mm:ss.fff"));
}
}
}
Besides the compiler support Microsoft has:
TAP among other things recommends a naming convention that async methods should have an Async suffix in method name.
Example with WebClient:
using System;
using System.Net;
using System.Threading.Tasks;
namespace AsyIO1
{
public class Program
{
public static void Main(string[] args)
{
WebClient wc = new WebClient();
for(int i = 0; i < 3; i++)
{
DateTime dt1 = DateTime.Now;
string google = wc.DownloadString("http://www.google.com/");
DateTime dt2 = DateTime.Now;
Console.WriteLine((int)(dt2 - dt1).TotalMilliseconds);
DateTime dt3 = DateTime.Now;
Task<string> th = wc.DownloadStringTaskAsync("http://www.google.com/");
DateTime dt4 = DateTime.Now;
string asygoogle = th.Result;
DateTime dt5 = DateTime.Now;
Console.WriteLine((int)(dt4 - dt3).TotalMilliseconds + " + " + (int)(dt5 - dt4).TotalMilliseconds);
}
}
}
}
Output:
3230 10 + 231 158 0 + 224 154 0 + 159
We see that it is Result that takes the time not DownloadStringTaskAsync that completed immediatetly.
Example with StreamReader:
using System;
using System.IO;
using System.Threading.Tasks;
namespace AsyIO2
{
public class Program
{
public static void Main(string[] args)
{
using(StreamWriter sw = new StreamWriter(@"C:\work\big.txt") )
{
for(int i = 0; i < 10000000; i++)
{
sw.WriteLine("12345678");
}
}
for(int i = 0; i < 3; i++)
{
StreamReader sr = new StreamReader(@"C:\work\big.txt");
DateTime dt1 = DateTime.Now;
string src = sr.ReadToEnd();
DateTime dt2 = DateTime.Now;
sr.Close();
Console.WriteLine((int)(dt2 - dt1).TotalMilliseconds);
StreamReader asysr = new StreamReader(@"C:\work\big.txt");
DateTime dt3 = DateTime.Now;
Task<string> th = asysr.ReadToEndAsync();
DateTime dt4 = DateTime.Now;
string asysrc = th.Result;
DateTime dt5 = DateTime.Now;
asysr.Close();
Console.WriteLine((int)(dt4 - dt3).TotalMilliseconds + " + " + (int)(dt5 - dt4).TotalMilliseconds);
}
}
}
}
Output:
476 79 + 6266 511 0 + 6200 533 0 + 6191
Again it is Result not ReadToEndAsync that takes the time.
The new HttpClient class uses TAP.
Example:
using System;
using System.Net.Http;
namespace E
{
public class Program
{
public static void Main(string[] args)
{
HttpClient hc = new HttpClient();
String google = hc.GetStringAsync("http://www.google.com//").Result;
Console.WriteLine(google);
}
}
}
This examples does not use await, but it can obviously be used.
I consider this to be a less important feature due to the existance of WebClient.
I predict that this will not be used much as most developers will just continue with WebClient.
Another big change in .NET 4.5 os the support for WInRT (and the new UI framework known as Metro but is actually named modern.
WinRT (Windows Runtime) is a new framework in Windows 8 and 2012. It is not the same as Windows RT, which is an ARM tablet version of Windows 8.
WinRT is native (unmanaged) code.
WinRT is COM based. WinRT components implements IUnknown like all COM components does and IInspectable which is specific for WinRT components. They do not implement IDispatch (used by VBS and JScript).
Meta data is not stored in a .tlb file like in the old days but instead in a .winmd file, which uses same format as .NET components.
.NET code can use WinRT components just like .NET components and .NET provide the required glue code.
WinRT is used by the socalled Modern UI apps.
Modern UI apps and traditional desktop apps are two very different programming models.
Illustrative figure: http://i.stack.imgur.com/y7uoI.png
But the change from C# WPF & SL to C# WinRT should be relative easy. Here are some tips: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/br229571.aspx
See .NET 4.6 and C# 6 New Features.
Version | Date | Description |
---|---|---|
1.0 | August 26th 2012 | Initial version (in Danish) published on Eksperten.dk |
2.0 | July 14th 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 |
See list of all articles here
Please send comments to Arne Vajhøj