Related
I was wondering if it is possible to save C# code fragments to a text file (or any input stream), and then execute those dynamically? Assuming what is provided to me would compile fine within any Main() block, is it possible to compile and/or execute this code? I would prefer to compile it for performance reasons.
At the very least, I could define an interface that they would be required to implement, then they would provide a code 'section' that implemented that interface.
The best solution in C#/all static .NET languages is to use the CodeDOM for such things. (As a note, its other main purpose is for dynamically constructing bits of code, or even whole classes.)
Here's a nice short example take from LukeH's blog, which uses some LINQ too just for fun.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
class Program
{
static void Main(string[] args)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
parameters.GenerateExecutable = true;
CompilerResults results = csc.CompileAssemblyFromSource(parameters,
#"using System.Linq;
class Program {
public static void Main(string[] args) {
var q = from i in Enumerable.Range(1,100)
where i % 2 == 0
select i;
}
}");
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
}
The class of primary importance here is the CSharpCodeProvider which utilises the compiler to compile code on the fly. If you want to then run the code, you just need to use a bit of reflection to dynamically load the assembly and execute it.
Here is another example in C# that (although slightly less concise) additionally shows you precisely how to run the runtime-compiled code using the System.Reflection namespace.
You can compile a piece C# of code into memory and generate assembly bytes with Roslyn. It's already mentioned but would be worth adding some Roslyn example for this here. The following is the complete example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace RoslynCompileSample
{
class Program
{
static void Main(string[] args)
{
// define source code, then parse it (to the type used for compilation)
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(#"
using System;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
}");
// define other necessary objects for compilation
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
// analyse and generate IL code from syntax tree
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
// write IL code into memory
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
// handle exceptions
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
}
else
{
// load this 'virtual' DLL so that we can use
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
// create instance of the desired class and call the desired function
Type type = assembly.GetType("RoslynCompileSample.Writer");
object obj = Activator.CreateInstance(type);
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] { "Hello World" });
}
}
Console.ReadLine();
}
}
}
Others have already given good answers on how to generate code at runtime so I thought I would address your second paragraph. I have some experience with this and just want to share a lesson I learned from that experience.
At the very least, I could define an
interface that they would be required
to implement, then they would provide
a code 'section' that implemented that
interface.
You may have a problem if you use an interface as a base type. If you add a single new method to the interface in the future all existing client-supplied classes that implement the interface now become abstract, meaning you won't be able to compile or instantiate the client-supplied class at runtime.
I had this issue when it came time to add a new method after about 1 year of shipping the old interface and after distributing a large amount of "legacy" data that needed to be supported. I ended up making a new interface that inherited from the old one but this approach made it harder to load and instantiate the client-supplied classes because I had to check which interface was available.
One solution I thought of at the time was to instead use an actual class as a base type such as the one below. The class itself can be marked abstract but all methods should be empty virtual methods (not abstract methods). Clients can then override the methods they want and I can add new methods to the base class without invalidating existing client-supplied code.
public abstract class BaseClass
{
public virtual void Foo1() { }
public virtual bool Foo2() { return false; }
...
}
Regardless of whether this problem applies you should consider how to version the interface between your code base and the client-supplied code.
Found this useful - ensures the compiled Assembly references everything you currently have referenced, since there's a good chance you wanted the C# you're compiling to use some classes etc in the code that's emitting this:
(string code is the dynamic C# being compiled)
var refs = AppDomain.CurrentDomain.GetAssemblies();
var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
compileParams.GenerateInMemory = true;
compileParams.GenerateExecutable = false;
var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
var asm = compilerResult.CompiledAssembly;
In my case I was emitting a class, whose name was stored in a string, className, which had a single public static method named Get(), that returned with type StoryDataIds. Here's what calling that method looks like:
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
Warning: Compilation can be surprisingly, extremely slow. A small, relatively simple 10-line chunk of code compiles at normal priority in 2-10 seconds on our relatively fast server. You should never tie calls to CompileAssemblyFromSource() to anything with normal performance expectations, like a web request. Instead, proactively compile code you need on a low-priority thread and have a way of dealing with code that requires that code to be ready, until it's had a chance to finish compiling. For example you could use it in a batch job process.
I recently needed to spawn processes for unit testing. This post was useful as I created a simple class to do that with either code as a string or code from my project. To build this class, you'll need the ICSharpCode.Decompiler and Microsoft.CodeAnalysis NuGet packages. Here's the class:
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
public static class CSharpRunner
{
public static object Run(string snippet, IEnumerable<Assembly> references, string typeName, string methodName, params object[] args) =>
Invoke(Compile(Parse(snippet), references), typeName, methodName, args);
public static object Run(MethodInfo methodInfo, params object[] args)
{
var refs = methodInfo.DeclaringType.Assembly.GetReferencedAssemblies().Select(n => Assembly.Load(n));
return Invoke(Compile(Decompile(methodInfo), refs), methodInfo.DeclaringType.FullName, methodInfo.Name, args);
}
private static Assembly Compile(SyntaxTree syntaxTree, IEnumerable<Assembly> references = null)
{
if (references is null) references = new[] { typeof(object).Assembly, typeof(Enumerable).Assembly };
var mrefs = references.Select(a => MetadataReference.CreateFromFile(a.Location));
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
else
{
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
}
}
}
private static SyntaxTree Decompile(MethodInfo methodInfo)
{
var decompiler = new CSharpDecompiler(methodInfo.DeclaringType.Assembly.Location, new DecompilerSettings());
var typeInfo = decompiler.TypeSystem.MainModule.Compilation.FindType(methodInfo.DeclaringType).GetDefinition();
return Parse(decompiler.DecompileTypeAsString(typeInfo.FullTypeName));
}
private static object Invoke(Assembly assembly, string typeName, string methodName, object[] args)
{
var type = assembly.GetType(typeName);
var obj = Activator.CreateInstance(type);
return type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, args);
}
private static SyntaxTree Parse(string snippet) => CSharpSyntaxTree.ParseText(snippet);
}
To use it, call the Run methods as below:
void Demo1()
{
const string code = #"
public class Runner
{
public void Run() { System.IO.File.AppendAllText(#""C:\Temp\NUnitTest.txt"", System.DateTime.Now.ToString(""o"") + ""\n""); }
}";
CSharpRunner.Run(code, null, "Runner", "Run");
}
void Demo2()
{
CSharpRunner.Run(typeof(Runner).GetMethod("Run"));
}
public class Runner
{
public void Run() { System.IO.File.AppendAllText(#"C:\Temp\NUnitTest.txt", System.DateTime.Now.ToString("o") + "\n"); }
}
To compile you could just initiate a shell call to the csc compiler. You may have a headache trying to keep your paths and switches straight but it certainly can be done.
C# Corner Shell Examples
EDIT: Or better yet, use the CodeDOM as Noldorin suggested...
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Reflection;
namespace ASL
{
class Program
{
[Obsolete]
static void Main(string[] args)
{
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}";
Console.WriteLine(code);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
main.Invoke(null, null);
Console.ReadLine();
}
}
}
Can you give me some guidance to dynamically load class based on name. The name is provided as a argument at runtime.
static void Main(string[] args)
{
...
}
Let's say my argument is "parrot" then I would like to load my parrotProcessor class. If my argument name is "snake" then I load my To make snakeProcessor. Of course this mean I have a parrot and snake processor class that inherit an interface IProcessor. I don't know what could be the list of all processor. this list is maintained by other developers and they can create what they want.
Example of my processor interface:
public interface IProcessor
{
void Process();
}
And in my Program.cs
static void Main(string[] args)
{
var processor = GetProcessor(args[0]);
processor.Process();
}
My question is what should I do in GetProcessor() method?
Here is what I have at this moment:
private IProcessor GetProcessor(string name)
{
switch (name)
{
case "ant":
return new AntProcessor();
case "parrot":
return new ParrotProcessor();
case "snake":
return new SnakeProcessor();
default:
throw new ArgumentException("Case not found");
}
}
But this mean I must updated this ugly switch each time I create a new processor specialized class. This is not possible. I can do it now for development but not for long term.
What are the solutions? Should I use something similar to DI with NInject or am I mixing everything? Can I simply use the Invoke method? And why Invoke or DI? I know this question is kind of open question but it is something that happen often in code of many people so I suppose there is unique best practice about it.
You can use something like the following
var type = Type.GetType("MyFullyQualifiedTypeName");
var myObject = (MyAbstractClass)Activator.CreateInstance(type);
You need to do some string modifications like taking the word, adding the processor string and making sure that all the processors are at the same place.
If you are certain that the type is in the current assembly, simply fully qualified name by this
Activator.CreateInstance(Type.GetType("SomeProcessor"));
First of all, there is absolutely nothing wrong with using a switch block as you are doing. It gets the job done, and it serves as an explicit source of truth with regards to the interpretation of the command-line parameter. It also acts as a whitelist, preventing users from passing a class name that maybe you don't want them to instantiate. Yes, you have to update it every time you add a new class, but you're already adding the class itself, so you are already in a situation where a new version and deployment will be needed.
That being said, there are various reasons why you'd rather have the ability to look up a command line parameter and automatically know which type to instantiate. That is trivial to do with a Dictionary<string,Func<IProcessor>>:
this.Map = new Dictionary<string,Func<IProcessor>>
{
{ "ant", () => new AntProcessor() },
{ "snake", () => new SnakeProcessor() },
{ "parrot", () => new ParrotProcessor() },
{ "lizard", () => new LizardProcessor() }
};
Then you would handle a command-line parameter like this:
//Use the string to look up a delegate
var ok = this.Map.TryGetValue(textFromCommandline, out var func);
//If not found, user entered a bad string
if (!ok) throw new ArgumentException();
//Invoke the delegate to obtain a new instance
IProcessor processor = func();
return processor;
Once you understand the concept of using a map in this way, you can come up with a scheme to populate it automatically, e.g
this.Map = assembly.GetTypes()
.Where( t => typeof(IProcessor).IsAssignableFrom( t ))
.ToDictionary
(
t => t.Name,
t => new Func<IProcessor>( () => Activator.CreateInstance(t) as IProcessor );
);
And you will have met your goal of not having to maintain a hardcoded list anywhere.
You can rewrite private IProcessor GetProcessor(string name) method using a little mix of reflection and LINQ like this:
private IProcessor GetProcessor<Tinterface>(string name) where Tinterface : IProcessor
{
var type = typeof(Tinterface).Assembly.GetTypes()
.First(x => x.FullName.Contains("name"));
return (Tinterface)Activator.CreateInstance(type);
}
Usage:
static void Main(string[] args)
{
var processor = GetProcessor<IProcessor>(args[0]);
processor.Process();
}
This route saves you the stress of typing the fully qualified name of the class
You can try iterate over all exported types in specific assembly:
using System;
using System.Linq;
using System.Reflection;
namespace ConsoleApp
{
public class Program
{
public static void Main (string[] args)
{
Assembly assembly = typeof (Program).Assembly; // use current assembly...
var types = assembly.GetExportedTypes() // public types only
.Where (type => type.GetInterfaces().Contains (typeof (IProcessor))) // interface must be implemented
.Where (type => type.Name.EndsWith ("Processor")) // and maybe use some naming convention?
.ToList();
//string name = args[0];
string name = "Parrot";
Type parrotType = types.Where (x => x.Name.StartsWith (name)).FirstOrDefault();
if (parrotType != null)
{
// it will work only when we implement parameterless constructor for this type
IProcessor parrotInstance = (IProcessor) Activator.CreateInstance (parrotType);
parrotInstance.Process();
}
}
}
public interface IProcessor
{
void Process();
}
public class SnakeProcessor : IProcessor
{
public void Process()
{
}
}
public class ParrotProcessor : IProcessor
{
public void Process()
{
Console.WriteLine ("Parrot Process");
}
}
}
I will add to the answers that suggest using reflection : EX: IProcessor parrotInstance = (IProcessor) Activator.CreateInstance(parrotType); is to make this part of code in a separate Factory class for Processor this way you can reuse the factory class in other places in your code, also even if you decide to keep the switch statement, the changes on the factory class will only affect it without affecting any dependent code.
public interface IProcessorFactory
{
IProcessor GetProcessor(string processorTypeName);
}
Good read:
SOLID Design Principles
Recently one of our development teams started with dependency injection.
One thing I noticed is that (when initializing the Container) the code has a lot of places, where it uses a TransientLifetimeManager on a instance. The instance has been created explicitly by the developer a few lines before.
KalenderView kalenderView = new KalenderView(new KalenderViewModel());
unityContainer.RegisterInstance(kalenderView, new TransientLifetimeManager());
Personally I would rewrite it into two RegisterType calls, one for the ViewModel, one for the View, but this got my attention.
My question is: Will the code even do, what I would expect it to do?
It looks like it's creating a new object everytime a instance needs to be resolved (roughly explained). But that can't be right, can it? It would be "magic" for me, I don't think, unity can "analyse" and save the state of an object during registration, right?
I found nothing on whether it's possible to use TransientLifetimeManager on RegisterInstance. So, will it ignore the given manager and use the ContainerControlledLifetimeManager instead?
Let's write simple test:
namespace UnityTest
{
using System;
using Unity;
class Program
{
public class TestClass
{
public static int Version = 0;
public TestClass()
{
Version++;
Console.WriteLine(Version);
}
}
static void Main(string[] args)
{
var container = new UnityContainer();
var obj = new TestClass();
container.RegisterInstance(obj, new TransientLifetimeManager());
container.Resolve<TestClass>();
container.Resolve<TestClass>();
container.Resolve<TestClass>();
}
}
}
Will output:
1
2
3
4
So, container creates new instance per resolve.
You can even remove registration and it will work:
namespace UnityTest
{
using System;
using Unity;
class Program
{
public class TestClass
{
public static int Version = 0;
public TestClass()
{
Version++;
Console.WriteLine(Version);
}
}
static void Main(string[] args)
{
var container = new UnityContainer();
container.Resolve<TestClass>();
container.Resolve<TestClass>();
container.Resolve<TestClass>();
}
}
}
Will output:
1
2
3
Simple question; is it possible to ResolveAll<T>, for unregistered types?
In an ideal world, I'd have something similar to an IPluggable interface, which when resolved would return a collection of objects inheriting that interface.
// both unregistered types
public class PluginOne : IPluggable { }
public class PluginTwo : IPluggable { }
// returns instances of PluginOne and PluginTwo
IEnumerable<IPluggable> result = container.ResolveAll<IPluggable>
As far as I'm aware, it's achievable with alternatives such as StructureMap, but sadly our structure is built around Unity. The only solution I can think of is to create a bootstrapper to automatically register certain types using a bit of reflection and namespace mining?
Yes you are correct. Unity will not resolve any unregistered types (unless you ask for single instance of class not interface). And solution proposed - bootstrapper - is the one I use with success for many of my projects. The only problem I had was in selecting a list of dlls to scan which can be tricky if you want it to find extensions in your folder. The most save approach is to add a configuration section for this.
I created my own extension that resolves types based on my interface IBlock. The extension only looks in the executing assembly but could potentially look anywhere you want. From this it should be possible to make an extension that does what you want.
IBlock:
using Microsoft.Practices.Unity;
public interface IBlock
{
void Register(IUnityContainer unity);
}
Extension:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.Unity;
public class UnityBlockRegistrationExtender : UnityContainerExtension
{
private readonly NameToTypesMap nameToTypesMap = new NameToTypesMap();
protected override void Initialize()
{
var blockType = typeof(IBlock);
var blockTypes = Assembly.GetEntryAssembly().GetTypes()
.Where(block => blockType.IsAssignableFrom(block) && block.IsClass);
foreach (var type in blockTypes)
{
if (this.nameToTypesMap.AddType(type.AssemblyQualifiedName, type))
{
var block = this.Container.Resolve(type) as IBlock;
block.Register(this.Container);
}
}
}
private class NameToTypesMap
{
private readonly Dictionary<string, Type> map = new Dictionary<string, Type>();
internal bool AddType(string name, Type type)
{
if (name == null)
{
throw new ArgumentNullException("name", "A name is required.");
}
if (type == null)
{
throw new ArgumentNullException("type", "A Type object is required.");
}
lock (this.map)
{
if (!this.map.ContainsKey(name))
{
this.map[name] = type;
return true;
}
}
return false;
}
}
}
There is an extension for Unity that works very similar to Structure Map's config engine.
It allows you to scan assemblies for implementations of interfaces and gives you support for custom conventions as well.
I was wondering if it is possible to save C# code fragments to a text file (or any input stream), and then execute those dynamically? Assuming what is provided to me would compile fine within any Main() block, is it possible to compile and/or execute this code? I would prefer to compile it for performance reasons.
At the very least, I could define an interface that they would be required to implement, then they would provide a code 'section' that implemented that interface.
The best solution in C#/all static .NET languages is to use the CodeDOM for such things. (As a note, its other main purpose is for dynamically constructing bits of code, or even whole classes.)
Here's a nice short example take from LukeH's blog, which uses some LINQ too just for fun.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
class Program
{
static void Main(string[] args)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
parameters.GenerateExecutable = true;
CompilerResults results = csc.CompileAssemblyFromSource(parameters,
#"using System.Linq;
class Program {
public static void Main(string[] args) {
var q = from i in Enumerable.Range(1,100)
where i % 2 == 0
select i;
}
}");
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
}
The class of primary importance here is the CSharpCodeProvider which utilises the compiler to compile code on the fly. If you want to then run the code, you just need to use a bit of reflection to dynamically load the assembly and execute it.
Here is another example in C# that (although slightly less concise) additionally shows you precisely how to run the runtime-compiled code using the System.Reflection namespace.
You can compile a piece C# of code into memory and generate assembly bytes with Roslyn. It's already mentioned but would be worth adding some Roslyn example for this here. The following is the complete example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace RoslynCompileSample
{
class Program
{
static void Main(string[] args)
{
// define source code, then parse it (to the type used for compilation)
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(#"
using System;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
}");
// define other necessary objects for compilation
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};
// analyse and generate IL code from syntax tree
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
// write IL code into memory
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
// handle exceptions
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
}
else
{
// load this 'virtual' DLL so that we can use
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
// create instance of the desired class and call the desired function
Type type = assembly.GetType("RoslynCompileSample.Writer");
object obj = Activator.CreateInstance(type);
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] { "Hello World" });
}
}
Console.ReadLine();
}
}
}
Others have already given good answers on how to generate code at runtime so I thought I would address your second paragraph. I have some experience with this and just want to share a lesson I learned from that experience.
At the very least, I could define an
interface that they would be required
to implement, then they would provide
a code 'section' that implemented that
interface.
You may have a problem if you use an interface as a base type. If you add a single new method to the interface in the future all existing client-supplied classes that implement the interface now become abstract, meaning you won't be able to compile or instantiate the client-supplied class at runtime.
I had this issue when it came time to add a new method after about 1 year of shipping the old interface and after distributing a large amount of "legacy" data that needed to be supported. I ended up making a new interface that inherited from the old one but this approach made it harder to load and instantiate the client-supplied classes because I had to check which interface was available.
One solution I thought of at the time was to instead use an actual class as a base type such as the one below. The class itself can be marked abstract but all methods should be empty virtual methods (not abstract methods). Clients can then override the methods they want and I can add new methods to the base class without invalidating existing client-supplied code.
public abstract class BaseClass
{
public virtual void Foo1() { }
public virtual bool Foo2() { return false; }
...
}
Regardless of whether this problem applies you should consider how to version the interface between your code base and the client-supplied code.
Found this useful - ensures the compiled Assembly references everything you currently have referenced, since there's a good chance you wanted the C# you're compiling to use some classes etc in the code that's emitting this:
(string code is the dynamic C# being compiled)
var refs = AppDomain.CurrentDomain.GetAssemblies();
var refFiles = refs.Where(a => !a.IsDynamic).Select(a => a.Location).ToArray();
var cSharp = (new Microsoft.CSharp.CSharpCodeProvider()).CreateCompiler();
var compileParams = new System.CodeDom.Compiler.CompilerParameters(refFiles);
compileParams.GenerateInMemory = true;
compileParams.GenerateExecutable = false;
var compilerResult = cSharp.CompileAssemblyFromSource(compileParams, code);
var asm = compilerResult.CompiledAssembly;
In my case I was emitting a class, whose name was stored in a string, className, which had a single public static method named Get(), that returned with type StoryDataIds. Here's what calling that method looks like:
var tempType = asm.GetType(className);
var ids = (StoryDataIds)tempType.GetMethod("Get").Invoke(null, null);
Warning: Compilation can be surprisingly, extremely slow. A small, relatively simple 10-line chunk of code compiles at normal priority in 2-10 seconds on our relatively fast server. You should never tie calls to CompileAssemblyFromSource() to anything with normal performance expectations, like a web request. Instead, proactively compile code you need on a low-priority thread and have a way of dealing with code that requires that code to be ready, until it's had a chance to finish compiling. For example you could use it in a batch job process.
I recently needed to spawn processes for unit testing. This post was useful as I created a simple class to do that with either code as a string or code from my project. To build this class, you'll need the ICSharpCode.Decompiler and Microsoft.CodeAnalysis NuGet packages. Here's the class:
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
public static class CSharpRunner
{
public static object Run(string snippet, IEnumerable<Assembly> references, string typeName, string methodName, params object[] args) =>
Invoke(Compile(Parse(snippet), references), typeName, methodName, args);
public static object Run(MethodInfo methodInfo, params object[] args)
{
var refs = methodInfo.DeclaringType.Assembly.GetReferencedAssemblies().Select(n => Assembly.Load(n));
return Invoke(Compile(Decompile(methodInfo), refs), methodInfo.DeclaringType.FullName, methodInfo.Name, args);
}
private static Assembly Compile(SyntaxTree syntaxTree, IEnumerable<Assembly> references = null)
{
if (references is null) references = new[] { typeof(object).Assembly, typeof(Enumerable).Assembly };
var mrefs = references.Select(a => MetadataReference.CreateFromFile(a.Location));
var compilation = CSharpCompilation.Create(Path.GetRandomFileName(), new[] { syntaxTree }, mrefs, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
return Assembly.Load(ms.ToArray());
}
else
{
throw new InvalidOperationException(string.Join("\n", result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error).Select(d => $"{d.Id}: {d.GetMessage()}")));
}
}
}
private static SyntaxTree Decompile(MethodInfo methodInfo)
{
var decompiler = new CSharpDecompiler(methodInfo.DeclaringType.Assembly.Location, new DecompilerSettings());
var typeInfo = decompiler.TypeSystem.MainModule.Compilation.FindType(methodInfo.DeclaringType).GetDefinition();
return Parse(decompiler.DecompileTypeAsString(typeInfo.FullTypeName));
}
private static object Invoke(Assembly assembly, string typeName, string methodName, object[] args)
{
var type = assembly.GetType(typeName);
var obj = Activator.CreateInstance(type);
return type.InvokeMember(methodName, BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, args);
}
private static SyntaxTree Parse(string snippet) => CSharpSyntaxTree.ParseText(snippet);
}
To use it, call the Run methods as below:
void Demo1()
{
const string code = #"
public class Runner
{
public void Run() { System.IO.File.AppendAllText(#""C:\Temp\NUnitTest.txt"", System.DateTime.Now.ToString(""o"") + ""\n""); }
}";
CSharpRunner.Run(code, null, "Runner", "Run");
}
void Demo2()
{
CSharpRunner.Run(typeof(Runner).GetMethod("Run"));
}
public class Runner
{
public void Run() { System.IO.File.AppendAllText(#"C:\Temp\NUnitTest.txt", System.DateTime.Now.ToString("o") + "\n"); }
}
To compile you could just initiate a shell call to the csc compiler. You may have a headache trying to keep your paths and switches straight but it certainly can be done.
C# Corner Shell Examples
EDIT: Or better yet, use the CodeDOM as Noldorin suggested...
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Reflection;
namespace ASL
{
class Program
{
[Obsolete]
static void Main(string[] args)
{
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}";
Console.WriteLine(code);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
main.Invoke(null, null);
Console.ReadLine();
}
}
}