Using C# 6 features with CodeDomProvider (Roslyn)

codedomprovider .net core
csharpcodeprovider
microsoft net compilers microsoft codedom providers dotnetcompilerplatform
microsoft c# compiler
codedom vs roslyn
codedom c#
net compiler
roslyn .net core
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );

CompilerParameters objCompilerParameters = new CompilerParameters();

...

CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );

When I compile my files I get:

FileFunctions.cs(347): Error: Unexpected character '$'

Does anyone know how to get string interpolation working with CodeDom compiling?

I found this link: How to target .net 4.5 with CSharpCodeProvider?

So I tried:

     var providerOptions = new Dictionary<string, string>();
     providerOptions.Add( "CompilerVersion", "v4.0" );

     // Instantiate the compiler.
     CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );

But I still get the same error.

I also updated the target framework to .NET Framework 4.6.

NOTE: I can't specify "v4.5" or "v4.6" or I will get:

************** Exception Text **************
System.InvalidOperationException: Compiler executable file csc.exe cannot be found.
   at System.CodeDom.Compiler.RedistVersionInfo.GetCompilerPath(IDictionary`2 provOptions, String compilerExecutable)
   at Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
   at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames)
   at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromFile(CompilerParameters options, String[] fileNames)
   at Dynamic.CodeDOMCompiler.CompileAllCodeFiles() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\Core\CodeDOMCompiler.cs:line 93
   at NewForm.InitializeSystem() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 179
   at NewForm.NewForm_Load(Object sender, EventArgs e) in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 111
   at System.Windows.Forms.Form.OnLoad(EventArgs e)

I have tried using the suggestion by Thomas Levesque:

CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

But then I get:

************** Exception Text **************
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\bin\roslyn\csc.exe'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.get_CompilerName()
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.FromFileBatch(CompilerParameters options, String[] fileNames)
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames)
   at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromFile(CompilerParameters options, String[] fileNames)
   at Dynamic.CodeDOMCompiler.CompileAllCodeFiles() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\Core\CodeDOMCompiler.cs:line 87
   at NewForm.InitializeSystem() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 179
   at NewForm.NewForm_Load(Object sender, EventArgs e) in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 111
   at System.Windows.Forms.Form.OnLoad(EventArgs e)

I'm not sure why it is trying to look for "csc.exe" in a subfolder of my bin directory.

This path exists:

C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\roslyn

But it was looking for:

C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\bin\roslyn\csc.exe

The built-in CodeDOM provider doesn't support C# 6. Use this one instead:

https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/

It's based on Roslyn and supports the C# 6 features.

Just change this line:

CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );

to this:

CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

Code generation does not support C# 6 · Issue #755 · dotnet/orleans , This code generator does not support C# 6 and using some of the newer quite busy writing business code and I can live without C# 6 features in my grains. Using Roslyn CodeDOM provider to compile generated code to  2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\roslyn. But it was looking for: C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\bin\roslyn\csc.exe. Practice As Follows. The built-in CodeDOM provider doesn’t support C# 6. Use this one instead:

Update: March 2018

Word of caution, NuGet version 1.0.6 ... 1.0.8 will not copy the /roslyn folder to the build output directory on non-web projects. Best stick with 1.0.5 https://github.com/aspnet/RoslynCodeDomProvider/issues/38

Run-time compilation using C#6 features requires a new compiler, as @thomas-levesque mentioned. This compiler can be installed by using the nuget package Microsoft.CodeDom.Providers.DotNetCompilerPlatform.

For desktop applications, there's a problem. The ASP.NET team, in their infinite wisdom have hard-coded the path to the compiler as <runtime-directory>\bin\roslyn\csc.exe See discussion at https://github.com/dotnet/roslyn/issues/9483

If your desktop application is compiled to \myapp\app.exe, the roslyn compiler will be located at \myapp\roslyn\csc.exe, BUT THE CSharpCodeProvider WILL RESOLVE csc.exe as \myapp\bin\roslyn\csc.exe

As far as I can tell, you have two options

  1. Create a post-build and/or installation routine that will move the \roslyn subdirectory to \bin\roslyn.
  2. Fix the runtime code through reflection black magic.

Here is #2, by exposing the CSharpCodeProvider as a property in a utility class.

using System.Reflection;
using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;

static Lazy<CSharpCodeProvider> CodeProvider { get; } = new Lazy<CSharpCodeProvider>(() => {
    var csc = new CSharpCodeProvider();
    var settings = csc
        .GetType()
        .GetField("_compilerSettings", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(csc);

    var path = settings
        .GetType()
        .GetField("_compilerFullPath", BindingFlags.Instance | BindingFlags.NonPublic);

    path.SetValue(settings, ((string)path.GetValue(settings)).Replace(@"bin\roslyn\", @"roslyn\"));

    return csc;
});

Using C# 6 features in ASP.NET MVC 5 razor views, It replaces the CodeDOM provider with the new .NET compiler platform (aka Roslyn) compiler as a service API. After installing the nuget package  It's based on Roslyn and supports the C# 6 features. Just change this line: CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" ); to this: CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

Compilation Configuration and Language Support, Check out the Roslyn GitHub Wiki to see which C# language version is supported language features to the highest major version (e.g. C# 7.0 for VS 2017), but this Since DotNetCompilerPlatform 1.0.6, a project-specific AppSetting (in the  Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP.NET runtime compilation) as well as improving the compilation performance of these systems. Please see the blog Enabling the .NET Compiler Platform

Updated information: even after releasing FW 4.8 you still not able to use all new features of C# 8.0 - distro contains CSC, limited to version 5.0; But there is hack to use CSC, distributed with VS2019 (yes, you have to install it):

var csprovider = new CSharpCodeProvider(new Dictionary<string,string> {
    ["CompilerDirectoryPath"] = @"c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn",
});
options += " -langversion:8.0 ";

var par = new CompilerParameters { GenerateInMemory = true, CompilerOptions = options };
par.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
par.ReferencedAssemblies.Add("System.Core.dll");

var res = csprovider.CompileAssemblyFromSource(par, "your C# code");

return res.CompiledAssembly;// <- compiled result

BTW despite explicit option 'GenerateInMemory', your code anyway will be written to the file and only then will be compiled. Keep in mind if you want your application run w/o disk access.

Replace CodeDom with Roslyn but “bin\roslyn\csc.exe not found!”, For faster compilation and support version 6 or higher of C# we for new language features in systems using CodeDOM (e.g. ASP.NET  C# 6 is the version of C# that ships with VS 2015 Preview. The philosophy behind this version is straightforward: improve simple everyday coding scenarios, without adding much conceptual baggage.

Faced the same issue of the completely broken compiler and found a third solution in addition to those listed in the Aaron's answer, by looking at the decompiled source of the library I found that, before setting the hardcoded path {ProgramLocation}\bin\roslyn it searches for an environment variable (also hardcoded) for that location, and if set, it uses that instead.

With that in mind, some code like this would also "fix" the problem:

//Set hardcoded environment variable to set the path to the library
Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", "actual compiler location goes here", EnvironmentVariableTarget.Process);
//Create compiler object
CSharpCodeProvider compiler = new CSharpCodeProvider();
//Clean up
Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null, EnvironmentVariableTarget.Process);

//Use "compiler" variable to actually compile the dynamic code

While this doesn't resorts to reflection to mess with the internals, it still relies on implementation details and abusing environment variables like this just feels wrong. I personally like this more than the reflection alternative, but at the same time I know that both relies on the exact implementation (as well as the hardcoded path).

Because of this issue, and the need to call an external program to do what should be done in-process, I still consider this library to be completely broken.

Distributing application with RoslynCodeDomProviderUsing C# 6 , Using C# 6 features with CodeDomProvider (rosyln)How to run Roslyn instead csc.exe from command exeRoslyn compiler looking in wrong bin folder for vbc. Following up on #755 I have modified ClientGenerator to use "Roslyn" to compile generated C# and VB.NET code. However, there are some issues: Because the Orleans project is bootstrapped using code generation I had to add the "Roslyn" NuGet package to the Orleans project but it is only used during the bootstrap process.

-langversion (C# Compiler Options), 6, The compiler accepts only syntax that is included in C# 6.0 or lower. NET Framework releases, the new syntax and features are not  When we first implemented collection initializers in C#, the Add methods that get called couldn’t be extension methods. VB got it right from the start, but it seems we forgot about it in C#. This has been fixed: the code generated from a collection initializer will now happily call an extension method called Add. It’s not much of a feature, but it’s occasionally useful, and it turned out implementing it in the new compiler amounted to removing a check that prevented it.

Microsoft.CodeDom.Providers , NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP. Here you will find task-focused samples in C#, JavaScript and TypeScript to help you get started with the Bot Framework SDK 2.0.0, 5,534,067, 6/4/2018. Keep in mind that removing these packages will break the use of C# 6 features. @RanjanKumar: Open your csproj file in a text editor and remove the nodes corresponding to the NuGet packages described in Kemal's answer. This might include Import nodes, Target nodes (EnsureNugetPackageBuildImports), and Reference nodes.

CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions ); mais je continue obtenir la même erreur. j'ai également mis à jour le cadre cible en .net cadre 4.6. NOTE: je ne peux pas spécifier "v4.5" ou "v4.6" ou je vais obtenir:

Comments
  • What .NET Framework version your project is target?
  • I updated my question with the details ".NET Framework 4.6". I should point out that the same code compiles just fine in Visual Studio, but it is when I try to compile it using CodeDom that the problem occurs.
  • This feature depends on the C# language version, not the .NET Framework version.
  • Not sure why this question was downvoted. It's a legitimate question, and the answer isn't obvious.
  • By copying the "roslyn" folder to the spot where it expected it - I was able to get this working. It seems like a hack though. I don't know if it is a bug in where the files are copied to, or a bug in where it is looking for the compiler.
  • "The built-in CodeDOM provider doesn't support C# 6": can you provide sources of that information for further consideration? Seems strange for me that CSharpCodeProvider don't use new compiler with 6 /langversion
  • By copying the "roslyn" folder to the spot where it expected it - I was able to get this working. It seems like a hack though. I don't know if it is a bug in where the files are copied to, or a bug in where it is looking for the compiler.
  • @LeonidVasilyev, I saw this recently, but I can't remember where... sorry.
  • @Derek, why "copy the roslyn folder"? Can't you just add the package via NuGet?
  • I did add the package via NuGet. But when running it seemed to be looking for csc.exe in the wrong location. If you see the two paths mentioned above you can see the difference. So I just copied the whole rosyln folder to the spot it seemed to be looking ( as a workaround ).
  • Thank you very much! This fixed my problem :)
  • When using this hack, remember to use version 1.0.5 or previous of NuGet package Microsoft.CodeDom.Providers.DotNetCompilerPlatform.
  • Why, have they fixed something ?
  • @Mustafa why should we use version 1.0.5 and less?