Unity C# 5.0 and 6.0 Integration /

Filename Size Date modified Message
CSharp vNext Support Solution
Unity C# 7 Demo Project
188 B
Fixed racing condition between UnityScheduler.Initialize() and AsyncTools type initialization.
2.0 KB
Added tag CSharpXXSupport 2.0.6 for changeset 920e921fbdac
2.0 MB
Updated readme
9.1 KB
Fixed readme. Resolving issue #16.

Can I use C# 5/6/7 in Unity?

Yes, you can.

Unity has been stuck with CLR 2.0 for a very long time, but almost all the latest C# features do not require the latest versions of CLR. Microsoft and Mono compilers can compile C# 5/6/7 code for CLR 2.0 if you explicitly ask them to do so.

Late binding (dynamic) feature that came with C# 4.0 still won't be available in Unity.

Ok, what should I do?

  • For C# 6.0

    1. Copy CSharp60Support folder from this repository (or the downloads page) to your Unity project. It should be placed in the project's root, next to the Assets folder.

    2. Import CSharp60Support.unitypackage into your project. It's located inside CSharp60Support folder.

    3. Select Reimport All or just restart the editor, whatever is faster in your case.

    4. [Optional] On Windows, run /CSharp60Support/ngen install.cmd once with administrator privileges. It will precompile csc.exe, pdb2mdb.exe and mcs.exe using Ngen that will make compilation in Unity a bit faster.

  • For C# 7.0 preview

    1. On MacOS download and install Mono 4.6+. On Windows download and install .Net Framework 4.6.2+.

    2. Copy CSharp70Support folder from this repository (or the downloads page) to your Unity project. It should be placed in the project's root, next to the Assets folder.

    3. Import CSharp70Support.unitypackage into your project. It's located inside CSharp70Support folder.

    4. Select Reimport All or just restart the editor, whatever is faster in your case.

    5. [Optional] On Windows, run /CSharp70Support/ngen install.cmd once with administrator privileges. It will precompile csc.exe, pdb2mdb.exe and mcs.exe using Ngen that will make compilation in Unity a bit faster.

Thus, the project folder is the only folder that changes. All the other projects will work as usual.

How does it work?

  1. /Assets/CSharp vNext Support/Editor/CSharpVNextSupport.dll is an editor extension that modifies the editor's internal data via reflection, telling it to use the alternative C# compiler (/CSharpXXSupport/CSharpCompilerWrapper.exe). If it doesn't exist, the stock compiler will be used.

  2. CSharpCompilerWrapper.exe receives and redirects compilation requests from Unity to one of the actual C# compilers using the following rules:

    • If CSharp70Support folder exists and contains Roslyn folder, then Roslyn C# 7.0 preview compiler will be used;

    • If CSharp60Support folder contains Roslyn folder, then Roslyn C# 6.0 compiler will be used;

    • else if CSharp60Support folder contains mcs.exe, then this Mono C# 6.0 compiler will be used;

    • else the stock compiler will be used (/Unity/Editor/Data/Mono/lib/mono/2.0/gmcs.exe).

To make sure that CSharpCompilerWrapper.exe does actually work, check its log file: UnityProject/CSharpXXSupport/compilation.log

Response (.rsp) files

If you want to use a response file to pass extra options to the compiler (e.g. -unsafe), the file must be named CSharpCompilerWrapper.rsp.

What platforms are "supported"?

This hack seems to work on the major platforms:

  • Windows (editor and standalone)
  • MacOS (editor and standalone)
  • Android
  • iOS

On MacOS the Roslyn compiler cannot create debug information files (.pdb) that Unity can consume. If you compile your code with Roslyn on MacOS you won't be able to debug it.

Since WebGL doesn't offer any multithreading support, AsyncBridge and Task Parallel Library are not available for this platform. Caller Info attributes are also not available, because their support comes with AsyncBridge library.

AsyncBridge/TPL stuff is also not compatible with Windows Store Application platform (and probably all the platforms that use .Net runtime instead of Mono runtime) due to API differences between the recent versions of .Net Framework and the ancient version of TPL (System.Threading.dll) that comes with AsyncBridge. Namely, you can't use async/await, Caller Info attributes and everything from System.Threading.dll (concurrent collections for example).

Making builds from command line

If you want to build your project from command line the simple way, it works as usual. For example,

    unity.exe -buildWindows64Player <pathname>

However, if you use Build Player Pipeline, you'll have to take extra steps, because otherwise the old compiler will be used and the build will fail:

  1. Make a copy of CSharpCompilerWrapper.exe and place it into /Unity/Editor/Data/Mono/lib/mono/2.0 on Windows or /unity.app/contents/mono/lib/mono/2.0 on Mac OS X.
  2. Rename this copy to smcs.exe.
  3. Make sure that in the Player Settings the API Compatibility Level option is set to NET 2.0.

Other known issues

  • C# 5.0/6.0 is not compatible with Unity Cloud Build service for obvious reason.

  • Using Mono C# 6.0 compiler may cause occasional Unity crashes while debugging in Visual Studio - http://forum.unity3d.com/threads/c-6-0.314297/page-2#post-2225696

  • IL2CPP doesn't support exception filters added in C# 6.0 (ExceptionFiltersTest.cs).

  • If a MonoBehaviour is declared inside a namespace, the source file should not contain any C# 6.0-specific language constructions before the MonoBehaviour declaration. Otherwise, the editor won't recognize the script as a MonoBehaviour component.

    Bad example:

    using UnityEngine;
    using static System.Math; // C# 6.0 syntax!
    
    namespace Foo
    {
       class Baz
       {
          object Qux1 => null; // C# 6.0 syntax!
          object Qux2 { get; } = null; // C# 6.0 syntax!
       }
    
        class Bar : MonoBehaviour { } // "No MonoBehaviour scripts in the file, or their names do not match the file name."
    }
    

    Good example:

    using UnityEngine;
    
    namespace Foo
    {
       class Bar : MonoBehaviour { } // ok
    
       class Baz
       {
          object Qux1 => null;
          object Qux2 { get; } = null;
       }
    }
    
  • There's a bug in Mono C# 6.0 compiler, related to null-conditional operator support (NullConditionalTest.cs):

    var foo = new[] { 1, 2, 3 };
    var bar = foo?[0];
    Debug.Log((foo?[0]).HasValue); // error CS1061: Type `int' does not 
    // contain a definition for `HasValue' and no extension method
    // `HasValue' of type `int' could be found. Are you missing an
    // assembly reference?
    

    Mono compiler thinks that foo?[0] is int while it's actually Nullable<int>. However, bar's type is deduced correctly - Nullable<int>.

License

All the source code is published under WTFPL version 2.

Want to talk about it?

http://forum.unity3d.com/threads/c-6-0.314297/#post-2108999

Random notes

  • Roslyn C# 6.0 compiler was taken from VS 2015 installation. C# 7.0 compiler was taken from VS 15 Preview 5 installation.

  • mcs.exe, pdb2mdb.exe and its dependencies were taken from Mono 4.4.1.0 installation. pdb2mdb.exe that comes with Unity is not compatible with the assemblies generated with Roslyn compiler.

  • AsyncBridge library contains a set of types that makes it possible to use async/await in projects that target CLR 2.0. It also provides Caller Info attributes support. For more information, check this blog post.

  • If you use async/await inside Unity events (Awake, Start, Update etc) you may notice that continuations (the code below await keyword) are executed in background threads. Most likely, this is not what you would want. To force await to return the execution to the main thread, you'll have to provide it with a synchronization context, like all WinForms and WPF applications do.

    Check UnityScheduler.cs, UnitySynchronizationContext.cs and UnityTaskScheduler.cs example implementations located in the project. These classes create and register several synchronization contexts for the Unity's main thread, so async/await could work the way they do in regular WinForms or WPF applications.

    For more information about what synchronization context is, what it is for and how to use it, see this set of articles by Stephen Toub: one, two, three.