How can I target a specific language version using CodeDOM? - c#

Using the C# code provider and the ICodeCompiler.CompileAssemblyFromSource method, I am attempting to compile a code file in order to produce an executable assembly.
The code that I would like to compile makes use of features such as optional parameters and extension methods that are only available when using the language C# 4.
Having said that, the code that I would like to compile only requires (and needs) to target version 2.0 of the .NET Framework.
Using the proceeding code it is possible to avoid any compile-time errors pertaining to syntax however, the resulting assembly will target version 4.0 of the framework which is undesirable.
var compiler = new CSharpCodeProvider(
new Dictionary<string, string> { { "CompilerVersion", "v4.0" } } );
How can I make is so that the code provider targets language version 4.0 but produces an assembly that only requires version 2.0 of the framework?

You need to instruct the C# compiler (that CSharpCodeProvider uses indirectly) that you want to link to another mscorlib.dll, using the /nostdlib option. Here is a sample that should do it:
static void Main(string[] args)
{
// defines references
List<string> references = new List<string>();
// get a reference to the mscorlib you want
var mscorlib_2_x86 = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
#"Microsoft.NET\Framework\v2.0.50727\mscorlib.dll");
references.Add(mscorlib_2_x86);
// ... add other references (System.dll, etc.)
var provider = new CSharpCodeProvider(
new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(references.ToArray(), "program.exe");
parameters.GenerateExecutable = true;
// instruct the compiler not to use the default mscorlib
parameters.CompilerOptions = "/nostdlib";
var results = provider.CompileAssemblyFromSource(parameters,
#"using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(""Hello world from CLR version: "" + Environment.Version);
}
}");
}
If you run this, it should compile a program.exe file. If you run that file, it should display something like this:
Hello world from CLR version: 2.0.50727.7905

Related

How to programmatically create a class library DLL using reflection?

Suppose my code possesses the knowledge about the metadata of a
nonexistent class library "mytest.dll", such as the types in this library, the functions of the types, the parameters and return types of the functions, etc.
How does my code manufacture this DLL using techniques such as reflection?
I know my code can generate the "mytest.cs" text file, then execute the compiler to produce the DLL, then delete the "mytest.cs" file. Just want to know if there are "more advanced" or "cooler" ways to do it.
Thanks.
There are 4 main steps in the process to compile and execute dynamic .net scripts from your application, even really complex scenarios can be simplified in this way:
Generate the code
Compile the script
Load the assembly
Execute the code
Lets generate a simple Hello Generated C# World App right now!:
Create a method that will generate an assembly that has 1 class called HelloWorldApp, this class has 1 method called GenerateMessage it will have X input parameters that will be integers, it will return a CSV string of the arguments that were passed in to it.
This solution requires the following package to be installed:
PM> Install-Package 'Microsoft.CodeAnalysis.CSharp.Scripting'
And will require the following using statements:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
Orchestration
The following method encapsulates the above steps:
private static void GenerateAndExecuteApp(int numberOfParameters)
{
string nameSpace = "Dynamic.Example";
string className = "HelloWorldApp";
string methodName = "GenerateMessage";
// 1. Generate the code
string script = BuildScript(nameSpace, className, methodName, numberOfParameters);
// 2. Compile the script
// 3. Load the Assembly
Assembly dynamicAssembly = CompileScript(script);
// 4. Execute the code
int[] arguments = Enumerable.Range(1, numberOfParameters).ToArray();
string message = ExecuteScript(dynamicAssembly, nameSpace, className, methodName, arguments);
Console.Out.WriteLine(message);
}
Generate the code
You say you already have item 1 sorted out, you can use StringBuilder, T4 templates or other mechanisms to generate the code files.
generating the code itself is its own question if you need help with that.
However, for our demo app, the following would work:
private static string BuildScript(string nameSpace, string className, string methodName, int numberOfParameters)
{
StringBuilder code = new StringBuilder();
code.AppendLine("using System;");
code.AppendLine("using System.Linq;");
code.AppendLine();
code.AppendLine($"namespace {nameSpace}");
code.AppendLine("{");
code.AppendLine($" public class {className}");
code.AppendLine(" {");
var parameterNames = Enumerable.Range(0, numberOfParameters).Select(x => $"p{x}").ToList();
code.Append($" public string {methodName}(");
code.Append(String.Join(",", parameterNames.Select(x => $"int {x}")));
code.AppendLine(")");
code.AppendLine(" {");
code.Append(" return $\"");
code.Append(String.Join(",", parameterNames.Select(x => $"{x}={{{x}}}")));
code.AppendLine("\";");
code.AppendLine(" }");
code.AppendLine(" }");
code.AppendLine("}");
return code.ToString();
}
For an input value of 3, the following code is generated:
using System;
using System.Linq;
namespace Dynamic.Example
{
public class HelloWorldApp
{
public string GenerateMessage(int p0,int p1,int p2)
{
return $"p0={p0},p1={p1},p2={p2}";
}
}
}
Compile the script (and Load it)
These are two discrete steps, however it is easiest to code them together in the same method, for this example we will ignore the generated dll and load the assembly directly into memory, that is generally the more likely use case for this type of scripting scenario anyway.
The hardest element of this is usually the referencing of the relevant dlls. There are a number of ways to achieve this, including loading all the dlls that are in the current executing context, I find a simple way to do this is to access the Assembly reference from the Type reference for the types we want to use inside the dynamic script:
List<string> dlls = new List<string> {
typeof(object).Assembly.Location,
typeof(Enumerable).Assembly.Location
};
Cut a long story short, this method compiles and loads the assembly into memory. It includes some crude compilation error handling, just to demonstrate how to do it:
private static Assembly CompileScript(string script)
{
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(script);
// use "mytest.dll" if you want, random works well enough
string assemblyName = System.IO.Path.GetRandomFileName();
List<string> dlls = new List<string> {
typeof(object).Assembly.Location,
typeof(Enumerable).Assembly.Location
};
MetadataReference[] references = dlls.Distinct().Select(x => MetadataReference.CreateFromFile(x)).ToArray();
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
// Now we actually compile the script, this includes some very crude error handling, just to show you can
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
List<string> errors = new List<string>();
foreach (Diagnostic diagnostic in failures)
{
//errors.AddDistinct(String.Format("{0} : {1}", diagnostic.Id, diagnostic.Location, diagnostic.GetMessage()));
errors.Add(diagnostic.ToString());
}
throw new ApplicationException("Compilation Errors: " + String.Join(Environment.NewLine, errors));
}
else
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
}
}
Execute the code
Finally, we can use reflection to instantiate an instance of the new app and then we can obtain a reference to the method and it. The name of the parameters is irrelevant, as long
we pass them through in the correct order:
for this demo the order is sort of irrelevant to, given they are all the same type ;)
private static string ExecuteScript(Assembly assembly, string nameSpace, string className, string methodName, int[] arguments)
{
var appType = assembly.GetType($"{nameSpace}.{className}");
object app = Activator.CreateInstance(appType);
MethodInfo method = appType.GetMethod(methodName);
object result = method.Invoke(app, arguments.Cast<object>().ToArray());
return result as string;
}
Output
The final output from all this for our method with 3 passed into it is:
p0=1,p1=2,p2=3
So that was super crude, you can bypass most of the indirect reflection aspects through the use of Interfaces. If your generated script inherits from types or interfaces that the calling code also has a strong reference to, then ExecuteScript in the above example might look like this:
private static string ExecuteScript(Assembly assembly, string nameSpace, string className)
{
var appType = assembly.GetType($"{nameSpace}.{className}");
object app = Activator.CreateInstance(appType);
if (app is KnownInterface known)
{
return known.GenerateMessage(1,2,3);
}
throw new NotSupportedException("Couldn't resolve known type");
}
The major benefit to using an interface or base class reference is that you can natively set properties or call other methods without having to reflect references to them all or to resort to using dynamic which would work, but becomes a bit harder to debug.
Of course the interface solution is hard to implement when we had a variable number of parameters, so that's not the best example, usually with dynamic scripts you would construct a known environment, say a known class and methods, but you might want to inject custom code into the body of the method.
It's a bit of fun in the end, but this simple example shows that C# can be used as a runtime scripting engine without too much trouble.

c# - compile c# code at runtime with roslyn

I checked some resource about roslyn,and i not found how to compile c# sources to executable with Roslyn.I can easily compile some .cs files to .exe using CodeDom:
/// <summary>
/// "anycpu" || "anycpu32bitpreferred" || "x86" || "x64" || "ARM" || "Itanium"
/// </summary>
public static string param = "anycpu";
public static string BCS(string[] sources,string[] libs,string outPath,bool exef)
{
var options = new Dictionary<string, string> {
{ "CompilerVersion", "v4.0.0" }
};
CSharpCodeProvider codeProvider = new CSharpCodeProvider(options);
CompilerParameters parameters = new CompilerParameters(libs);
parameters.GenerateExecutable = exef;
parameters.OutputAssembly = outPath;
parameters.CompilerOptions = "-platform:" + param;
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sources);
if (results.Errors.Count > 0)
{
string errsText = "";
foreach (CompilerError CompErr in results.Errors)
{
errsText = "("+CompErr.ErrorNumber +
")Line " + CompErr.Line +
",Column "+CompErr.Column +
":"+CompErr.ErrorText + "" +
Environment.NewLine;
}
return errsText;
}
else
{
return "Success";
}
}
but problem of CodeDom - he can compile only c# with .NET Framework 4.0,but i need to compile c# files with 4.6.1 .NET Framework version.So,question: Can i compile some c# files(.cs) with 4.6.1 .NET Framework version using Roslyn Compiler?
The CodeDom has been deprecated in favor of the Roslyn APIs. On .NET Framework (ie. .NET 4.x) you can continue to use the CSharpCodeProvider which uses the built in compiler which supports up to C# 6 if memory serves. If you want to use C# versions later than that you need to use Roslyn and there's a shim CodeProvider that uses Roslyn that gives you access to later C# versions.
Here's what this looks like using either the 'classic' provider or Roslyn provider with the CodeDom:
if (CompilerMode == ScriptCompilerModes.Roslyn)
// NuGet Package: Microsoft.CodeDom.Providers.DotNetCompilerPlatform
_compiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
else
_compiler = new Microsoft.CSharp.CSharpCodeProvider(); // classic
Ultimately though the CodeProvider interface is deprecated and it's a better idea to use the Roslyn APIs directly.
There's a lot more info both on using the old CSharpCodeProvider with Roslyn and using the Roslyn APIs in this post of mine.

How to properly setup CodeContext of IronPython to directly invoke IO from C#?

I am trying to directly invoke IronPython's built-in modules from C#. It looks like I'm missing some important initialization, that I can't find anywhere in the code.
Here's what I do:
namespace py.consoleio
{
using IronPython.Runtime;
using Microsoft.Scripting.Hosting;
using Microsoft.Scripting.Hosting.Providers;
using Microsoft.Scripting.Runtime;
public static class consoleio
{
public static string name;
static void Main()
{
var setup = new ScriptRuntimeSetup();
setup.LanguageSetups.Add(
IronPython.Hosting.Python.CreateLanguageSetup(null));
var dlrRuntime = new ScriptRuntime(setup);
var scriptDomainManager = HostingHelpers.GetDomainManager(dlrRuntime);
var pythonContext = new PythonContext(scriptDomainManager, null);
var context = new CodeContext(new PythonDictionary(), new ModuleContext(new PythonDictionary(), DefaultContext.DefaultPythonContext));
name = IronPython.Modules.Builtin.input(context, "What is your name?\n");
IronPython.Modules.Builtin.print(context, "Hi, %s.", consoleio.name);
System.GC.KeepAlive(pythonContext);
}
}
}
That properly outputs "What is your name?", but then crashes trying to decode input: unknown encoding: cp437.
Now I've already found, that encodings are initialized in Src/StdLib/Lib/encodings/init.py
I can't find how it gets to loading this module in a normal IronPython run (e.g. a console host), so I can't reproduce it in C# program.
My goal here is to invoke IronPython functions without dynamic dispatch.
UPD. Now I also tried to do this:
var engine = Python.CreateEngine();
this.ScriptDomainManager = HostingHelpers.GetDomainManager(engine.Runtime);
to the same result
Figured that one out: encodings module is implemented in Python in IronPython (core modules are in C#). It always worked with IronPythonConsole project, because it implicitly adds IronPython source for standard libraries to Python path. I just had to explicitly specify path like this:
var options = new Dictionary<string, object> { ["SearchPaths"] = path };
var engine = Python.CreateEngine(options);

How to achieve `FSharpValue.GetUnionFields` in a C# PCL (Profile 259)

I'm in a C# shared project trying to find the PCL (Profile 259) equivalent for FSharpValue.GetUnionFields.
In object browser via the C# project, I see
namespace Microsoft.FSharp.Reflection
{
[AutoOpen]
[CompilationMapping(SourceConstructFlags.Module)]
public static class FSharpReflectionExtensions
{
public static Tuple<UnionCaseInfo, object[]> FSharpValue.GetUnionFields.Static(object value, Type unionType, [OptionalArgument] FSharpOption<bool> allowAccessToPrivateRepresentation);
}
}
This appears to be what I'm looking for, but I'm unable (or don't know how) to call it from C#. Via F#, if I open the namespace, I can call the extension FSharpValue.GetUnionFields. FSharpValue.GetUnionFields does not compile from a c# PCL. I'm not experienced with F# so it could be I'm just lacking some important piece of knowledge related to F# - C# interop?
For reference, this is what I see from a F# pcl.
[<AutoOpen>]
module Microsoft.FSharp.Reflection.FSharpReflectionExtensions
open Microsoft.FSharp.Reflection
val GetUnionFields : value:obj * unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo * obj []
Repro project here:
https://github.com/kennethito/StackOverflowReferences/tree/master/FSharpValue-GetUnionFields
Again, this requires using reflection. Since it's a PCL, it's particularly nasty, as the actual version of FSharp.Core loaded at runtime is the one that will matter.
The following should work:
public static Tuple<UnionCaseInfo, object[]> TestIt()
{
var option = new FSharpOption<int>(123);
MethodInfo method;
try
{
// If "4.4.0.0" is loaded at runtime, get directly
var t = typeof(FSharpValue);
method = t.GetRuntimeMethods().First(mi => mi.Name == "GetUnionFields");
}
catch
{
var t = typeof(FSharpReflectionExtensions);
method = t.GetRuntimeMethods().First(mi => mi.Name == "FSharp.Value.GetUnionFields.Static");
}
return (Tuple<UnionCaseInfo, object[]>)method.Invoke(null, new object[] { option, option.GetType(), null });
}
This tries to find the method directly on the type (how it's specified in FSharp.Core 4.4), and falls back to the PCL structure (as an extension method).
The following C# console application shows it working:
static void Main(string[] args)
{
Tuple<UnionCaseInfo, object[]> results = CsharpPortable.Test.TestIt();
var uci = results.Item1;
Console.WriteLine("{0}:", uci.Name);
foreach (var pi in uci.GetFields())
{
Console.WriteLine("Property: {0}", pi.Name);
}
Console.ReadKey();
}

Compile simple string

Was just wondering if there are any built in functions in c++ OR c# that lets you use the compiler at runtime? Like for example if i want to translate:
!print "hello world";
into:
MessageBox.Show("hello world");
and then generate an exe which will then be able to display the above message? I've seen sample project around the web few years ago that did this but can't find it anymore.
It is possible using C#. Have a look at this Sample Project from the CodeProject.
Code Extract
private Assembly BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
public object ExecuteCode(string code, string namespacename, string classname, string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
In C++ you can't use the compiler at runtime but you can embed an interpreter in your project, like CINT.
You can always do it in the dirty way, with system() and calling the compiler "gcc..." or your equivalent
Nick's suggestion is good, but there is an alternative which is probably simpler to implement (but might not be appropriate for all projects). If you can assume that your user has a compiler installed you can generate a file and then compile it using their compiler.
The .NET-framework provides a few classes which give you access to compilers and code generators for C# and VB.NET, resulting in either an assembly loaded into memory or a simple .exe-file. See CSharpCodeProvider and this article.
Alternately, you can just create the source files and compile them manually (command-line calls (system) to the compiler, makefiles).
Concerning the translation of your source: You'll have to use parsing mechanisms like regular expressions here, or use a compiler-compiler tool like Coco/R, yacc etc. (Note that under C++, boost::spirit can also be quite useful)
In C# you can create a .NET "CodeDom" tree and then compile this using the .NET compiler. This gives you full access to most features of .NET.
See the "System.CodeDom" namespace or the MSDN help for CodeCompileUnit for details.

Categories

Resources