Skip to content

C# 6 support

Oleg Shilo edited this page Mar 24, 2017 · 2 revisions

Support for C# 6 syntax

Note this page describes how to enable C# 6 support for standalone script execution. For the script hosting scenarios please see Hosted Script Execution.

Usage

Starting from v3.9.15 CS-Script does support execution of C# 6.0 scripts. However due to the unstable (and slow) nature of the current MS solution for C# 6.0 hosted compilation it is disabled by default.

If you want to enable it you need set CSSCodeProvider.v.4.6.dll as your CS-Script code compiler. You can do this either globally via configuration console (not recommended) or per script with //css_args directive:

//css_args /provider:%CSSCRIPT_DIR%\lib\CSSCodeProvider.v4.6.dll 
using System;

class Script
{
    static void Main(string[] args)
    {
        int count = 333;
        Console.WriteLine($"Count: {count}");
    }
}

Global configuration image

Background

Unfortunately due to the MS shocking decision not to implement C# 6.0 dynamic compilation with CodeDOM this feature was very difficult to implement in CS-Script.

The problem is due to the fact that MS decided not to distribute any more Microsoft.CodeDom.Providers for C# (6.0) after doing this for the last 15 years for early versions. You've hired right. If in your application (built with C# 6.0) you use CodeDOM C# compiler for building the assembly from the C# source it will not allow v6.0 syntax but only v5.0.

For people who needs C# 6.0 compilation MS advises using NuGet package (CodeDOM Providers for .NET Compiler Platform ("Roslyn")) instead. Leaving along the deployment implications the package doesn't work just out of box. Meaning that today there is no a solid working solution for C# 6.0 hosted compilation.

Roslyn CSharpCodeProvider throws the error "cannot find csc.exe". After some experiments and analysis of Roslyn sources I found that it uses hard-codded csc.exe path. And this path is a relative one but not to the current directory but to the AppDomain.CurrentDomain.BaseDirectory!!!! Meaning that nothing you can do to change it.

MS's CompilationSettings.cs

internal static class CompilationSettingsHelper {
    private static ICompilerSettings _csc = new CompilerSettings(CompilerFullPath(@"bin\roslyn\csc.exe"), DefaultCompilerServerTTL);
    ... 
    private static string CompilerFullPath(string relativePath) {
        string compilerFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath);
        return compilerFullPath;
    }
}

There is a CompilerSettings class that supposed to allow customization of the complete compiler path but it pedantically made private so no one can use it. Brilliant!

In order to solve the problem one has to use reflection to actually fix the compiler path. This is how CS-Script does it:

using roslyn=Microsoft.CodeDom.Providers.DotNetCompilerPlatform;

static class RoslynExtensions
{
    public static void SetCompilerPath(this roslyn.CSharpCodeProvider provider, string path)
    {
        var flags = BindingFlags.NonPublic | BindingFlags.Instance;
        var settings = provider.GetType()
                               .GetField("_compilerSettings", flags)
                               .GetValue(provider);
        settings.GetType()
                .GetField("_compilerFullPath", flags)
                .SetValue(settings, path);
    }
}

And to make thing worth, the compilation using NuGet package CodeDOM providers is significantly slower then using standard providers for early versions of C#.

Of course Roslyn team will eventually fix these mistakes but it is very disappointing nevertheless as it does confirm that Roslyn isn't fully matured yet. Even after being 6 years in making.