I want to compile a C# console application inside my application and get the returned result somehow. I want this to happen silently(i don't want the console to actually show etc.) Lets say i have this code
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;
}
}
How would i execute the assembly and get the results?
Here's something I found -
public object ExecuteCode(string code, string namespacename, string classname, string functionname, bool isstatic, params object[] args)
{
var asm = BuildAssembly(code);
object instance = null;
Type type;
if(isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
return type.GetMethod(functionname).Invoke(instance, args);
}
This method simply extends your BuildAssembly function.
Source
Related
Trying to compile simple C# code at runtime on .NET Core but have this error:
System.PlatformNotSupportedException: 'Operation is not supported on
this platform.'
on this line:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
My code:
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Text;
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}
";
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
parameters.GenerateInMemory = true;
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);
I recommend using the Roslyn compiler. You'll need to add references Microsoft.CodeAnalysis and Microsoft.CodeAnalysis.CSharp for the following example to work. Note, that the RoslynCompiler class loads the assembly dynamically. You can modify the class fairly easily to use a FileStream instead of a MemoryStream if you want to save the compilation to disk for reuse.
Sample Usage of RoslynCompiler Class (below)
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
Console.WriteLine(\"Hello, world!\");
}
public static void WithParams(string message)
{
Console.WriteLine(message);
}
}
}
";
var compiler = new RoslynCompiler("First.Program", code, new[] {typeof(Console)});
var type = compiler.Compile();
type.GetMethod("Main").Invoke(null, null);
//result: Hellow World!
// pass an object array to the second null parameter to pass arguments
type.GetMethod("WithParams").Invoke(null, new object[] {"Hi there from invoke!"});
//result: Hi from invoke
Roslyn Compiler Class (Quick and Dirty Example)
public class RoslynCompiler
{
readonly CSharpCompilation _compilation;
Assembly _generatedAssembly;
Type? _proxyType;
string _assemblyName;
string _typeName;
public RoslynCompiler(string typeName, string code, Type[] typesToReference)
{
_typeName = typeName;
var refs = typesToReference.Select(h => MetadataReference.CreateFromFile(h.Assembly.Location) as MetadataReference).ToList();
//some default refeerences
refs.Add(MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll")));
refs.Add(MetadataReference.CreateFromFile(typeof(Object).Assembly.Location));
//generate syntax tree from code and config compilation options
var syntax = CSharpSyntaxTree.ParseText(code);
var options = new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
allowUnsafe: true,
optimizationLevel: OptimizationLevel.Release);
_compilation = CSharpCompilation.Create(_assemblyName = Guid.NewGuid().ToString(), new List<SyntaxTree> { syntax }, refs, options);
}
public Type Compile()
{
if (_proxyType != null) return _proxyType;
using (var ms = new MemoryStream())
{
var result = _compilation.Emit(ms);
if (!result.Success)
{
var compilationErrors = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error)
.ToList();
if (compilationErrors.Any())
{
var firstError = compilationErrors.First();
var errorNumber = firstError.Id;
var errorDescription = firstError.GetMessage();
var firstErrorMessage = $"{errorNumber}: {errorDescription};";
var exception = new Exception($"Compilation failed, first error is: {firstErrorMessage}");
compilationErrors.ForEach(e => { if (!exception.Data.Contains(e.Id)) exception.Data.Add(e.Id, e.GetMessage()); });
throw exception;
}
}
ms.Seek(0, SeekOrigin.Begin);
_generatedAssembly = AssemblyLoadContext.Default.LoadFromStream(ms);
_proxyType = _generatedAssembly.GetType(_typeName);
return _proxyType;
}
}
}
Performance Tip
If performance matters, use delegates as opposed to Invoke as follows to achieve near pre-compiled throughput:
void Main()
{
string code = #"OMITTED EXAMPLE CODE FROM SAMPLE ABOVE";
var compiler = new RoslynCompiler("First.Program", code, new[] { typeof(Console) });
var type = compiler.Compile();
// If perf matters used delegates to get near pre-compiled througput vs Invoke()
var cachedDelegate = new DynamicDelegateCacheExample(type);
cachedDelegate.Main();
//result: Hellow world!
cachedDelegate.Main("Hi there from cached delegate!");
//result: Hi there from cached delegate!
}
public class DynamicDelegateCacheExample
{
delegate void methodNoParams();
delegate void methodWithParamas(string message);
private static methodNoParams cachedDelegate;
private static methodWithParamas cachedDelegateWeithParams;
public DynamicDelegateCacheExample(Type myDynamicType)
{
cachedDelegate = myDynamicType.GetMethod("Main").CreateDelegate<methodNoParams>();
cachedDelegateWeithParams = myDynamicType.GetMethod("WithParams").CreateDelegate<methodWithParamas>();
}
public void Main() => cachedDelegate();
public void Main(string message) => cachedDelegateWeithParams(message);
}
With .net core netstandard and publishing to a self contained exe there are a couple more tricks you'll need;
public static ModuleMetadata GetMetadata(this Assembly assembly)
{
// based on https://github.com/dotnet/runtime/issues/36590#issuecomment-689883856
unsafe
{
return assembly.TryGetRawMetadata(out var blob, out var len)
? ModuleMetadata.CreateFromMetadata((IntPtr)blob, len)
: throw new InvalidOperationException($"Could not get metadata from {assembly.FullName}");
}
}
#pragma warning disable IL3000
public static MetadataReference GetReference(this Assembly assembly)
=> (assembly.Location == "")
? AssemblyMetadata.Create(assembly.GetMetadata()).GetReference()
: MetadataReference.CreateFromFile(assembly.Location);
#pragma warning restore IL3000
public static Assembly Compile(string source, IEnumerable<Type> references)
{
var refs = new HashSet<Assembly>(){
typeof(object).Assembly
};
foreach (var t in references)
refs.Add(t.Assembly);
foreach (var a in AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic
&& a.ExportedTypes.Count() == 0
&& (a.FullName.Contains("netstandard") || a.FullName.Contains("System.Runtime,"))))
refs.Add(a);
var options = CSharpParseOptions.Default
.WithLanguageVersion(LanguageVersion.Latest);
var compileOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
var compilation = CSharpCompilation.Create("Dynamic",
new[] { SyntaxFactory.ParseSyntaxTree(source, options) },
refs.Select(a => a.GetReference()),
compileOptions
);
using var ms = new MemoryStream();
var e = compilation.Emit(ms);
if (!e.Success)
throw new Exception("Compilation failed");
ms.Seek(0, SeekOrigin.Begin);
var context = new AssemblyLoadContext(null, true);
return context.LoadFromStream(ms);
}
// for dynamically implementing some interface;
public static C CompileInstance<C>(string source, IEnumerable<Type> references)
{
var assembly = Compile(source, references);
var modelType = assembly.DefinedTypes.Where(t => typeof(C).IsAssignableFrom(t)).Single();
return (C)Activator.CreateInstance(modelType);
}
I'll try to define as mush as possible my problem and forget nothing.
For my project, which use a webRequest, I would like to compile dynamically my webRequest.
For this I used the CodeDomProvider in a Private Assembly and a public MethodInfo who gives me back a " method" that I can use in my main program.
So the main problem is that in my CompileCode, my MethodInfo method = type.getMethod(functionname); gives me a NullReferenceException error. I know it's because my type.getMethod(functionname) can't work on a type which is null. I tried to modify the fact that my object instance and Type type are not null, but I can't give them values because of their gender and I get stuck in the fact that they stay null and gives me no values...
I also saw that lot of people used Linq, but as I am compiling a whole .cs file, I can't write it all like this with the #"using System.Linq;";
So here are the partial code were the problem is :
Thank you
namespace testCodeCompiler
{
public class CodeCompiler
{
public CodeCompiler()
{
}
public MethodInfo CompileCode(string code, string namespacename, string classname,string functionname, bool isstatic, params object[] args)
{
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); // here is the error
return method;
}
private Assembly BuildAssembly(string code)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
compilerparams.ReferencedAssemblies.Add("System.dll");
compilerparams.ReferencedAssemblies.Add("System.Xml.dll");
System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
compilerparams.ReferencedAssemblies.Add(currentAssembly.Location);
CompilerResults results = provider.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;
}
}
}
And a little part of the Main() :
static void Main(string[] args)
{
MethodInfo method;
[// Little bit of code ]
StreamReader sr = new StreamReader(#"c:\pathtothefileIwant\File.cs", System.Text.Encoding.Default);
string file = sr.ReadToEnd();
sr.Close();
CodeCompiler cc = new CodeCompiler();
object[] arguments = { popup }; // here are the args which are in another class
[...little bit of code...]
method = cc.CompileCode(file, "testNamespace", "Class1", "webRequest", true, arguments);
List<Test> li = (List<Test>)method.Invoke(null, arguments); // Here I invoke the method to put it in a List<Compte> I made before.
}
The problem was in the class Program
Main(){ method = cc.CompileCode(file, "testNamespace", "Class1", "webRequest", true, arguments);}
The string classname was not the good one and didn't pointed to the real document I wanted to compile. The good path was method = cc.CompileCode(file,"testNamespace", "WebRequest","webRequest", true, arguments);}
That's why the Type type; couldn't get something instead of null.
Actually i want to run class file dynamically without restarting server
and i tried with the following code.
the below code works fine on localhost, but it does not works when published on server
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll", "System.Linq.dll", AppSession.Analytics.ServerMapPath + "/BITool.dll", "System.ComponentModel.DataAnnotations.dll", AppSession.Analytics.ServerMapPath + "/RDotNet.dll", AppSession.Analytics.ServerMapPath + "/DynamicInterop.dll", "System.Core.dll", AppSession.Analytics.ServerMapPath + "/System.Dynamic.dll" };
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams, code);
if (compile.Errors.HasErrors)
{
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors)
{
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
//ExpoloreAssembly(compile.CompiledAssembly);
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null)
{
mt = module.GetType("BITool.Concrete.RIntegration");
}
if (mt != null)
{
methInfo = mt.GetMethod("RConnectFn");
}
if (methInfo != null)
{
methInfo.Invoke(null, new object[] { });
}
Can anyone suggest me a method to achieve this??
Thanks for the messages about my first post about this problem. I will do a repost and try to be more clear this time. I guess this may be a trivial problem but I'm really stuck and need some help. This is my first time posting here.
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace DynamicCode
{
public class DynaCore
{
string WorkingCode =
"using System;"+
"using System.Collections.Generic;"+
"namespace DynaCore"+
"{"+
" public class DynaCore"+
" {"+
" static public string DynamicResult()"+
" {"+
" return \"I'm compiled\";"+
" }"+
" }"+
"}";
string PredicateTemplCode =
"using System;"+
"using System.Linq;"+
"using System.Collections.Generic;"+
"namespace DynaCore"+
"{"+
" public class DynaCore"+
" {"+
" static public Func<{1}, bool> DynamicResult()"+
" {"+
" return new Func<{1}, bool>({2});"+
" }"+
" }"+
"}";
public DynaCore()
{
string compiledString = WorkingCompilation(WorkingCode);
Func<bool, bool> compiladePredicate = NotWorkingCompilation<bool>(PredicateTemplCode, "(o)=> true");
}
string WorkingCompilation(string code)
{
var cParams = new CompilerParameters();
cParams.GenerateInMemory = true;
cParams.TreatWarningsAsErrors = false;
cParams.GenerateExecutable = false;
cParams.CompilerOptions = "/optimize /target:library";
var curAss = Assembly.GetExecutingAssembly();
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("mscorlib.dll");
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("System.Data.dll");
cParams.ReferencedAssemblies.Add(curAss.Location);
var provider = new CSharpCodeProvider();
var compalerResult = provider.CompileAssemblyFromSource(cParams, code);
if (compalerResult.Errors.HasErrors)
{
var complieError = "";
foreach (CompilerError ce in compalerResult.Errors)
complieError += ce + " ";
throw new Exception(complieError.Trim());
}
Module module = compalerResult.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
return (string)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}
Func<T, bool> NotWorkingCompilation<T>(string code, string predicateString)
{
var cParams = new CompilerParameters();
cParams.GenerateInMemory = true;
cParams.TreatWarningsAsErrors = false;
cParams.GenerateExecutable = false;
cParams.CompilerOptions = "/optimize /target:library";
var curAss = Assembly.GetExecutingAssembly();
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("mscorlib.dll");
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("System.Data.dll");
cParams.ReferencedAssemblies.Add("System.Core.dll");
cParams.ReferencedAssemblies.Add(curAss.Location);
var provider = new CSharpCodeProvider();
var codeToRun = code.Replace("{1}", typeof(T).Name).Replace("{2}", predicateString);
var compalerResult = provider.CompileAssemblyFromSource(cParams, codeToRun);
if (compalerResult.Errors.HasErrors)
{
var complieError = "";
foreach (CompilerError ce in compalerResult.Errors)
complieError += ce + " ";
throw new Exception(complieError.Trim());
}
Module module = compalerResult.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
return (Func<T, bool>)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}
}
}
The problem is that when I reference System.Core.dll in ReferencedAssemblies.Add("System.Core.dll"), it gives me a compiler error:
error CS0006: Metadata file 'System.Core.dll' could not be found
I'm using v3.5 and VS 2008.
Thanks for all the answers!
It turns out that CSharpCodeProvider defaults to version 2.0 that have no support for generics or linq. The following fixed the problem:
var provider = new CSharpCodeProvider(
new Dictionary<String, String>{{ "CompilerVersion","v3.5" }});
I thought I'd update this thread since it was never properly answered. I just came across the same issue (CS0006), having to include a WPF library that was in the WPF directory, and wound up fixing it with the following:
string ver = string.Format("{0}.{1}.{2}", Environment.Version.Major, Environment.Version.MajorRevision, Environment.Version.Build);
string exWpfDir = string.Format(#"C:\WINDOWS\Microsoft.NET\Framework\v{0}\WPF", ver);
string exDir = string.Format(#"C:\WINDOWS\Microsoft.NET\Framework\v{0}", ver);
CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
compilerparams.IncludeDebugInformation = false;
compilerparams.TreatWarningsAsErrors = false;
compilerparams.CompilerOptions = string.Format("/lib:{0}", exWpfDir);
compilerparams.CompilerOptions = string.Format("/lib:{0}", exDir);
Another issue may be that System.Core.dll is actually in a different location than the other dlls mentioned.
On my machine, System.Core.dll is located in %ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll, whereas the other dlls are in the GAC.
Sometimes you need to add the referenced assembly to the CSharpCodeProvider parameters.
parameters.ReferencedAssemblies.Add("System.dll");
Hope this helps.
The resulting code
using System;
using System.Linq;
using System.Collections.Generic;
namespace DynaCore
{
public class DynaCore
{
static public Func<Boolean, bool> Main()
{
Func<Boolean, bool> retur = (o) => true;
}
}
}
does not compile itself when pasted into a new file. First compilation error is
'DynaCore.DynaCore.Main()': not all code paths return a value
First you need to generate code thats compiling when pasted into a empty .cs file.
The first obvious thing is to fix the func-statement into something like
return new Func<Boolean, bool>(o => true);
Edit:
And don't call the method Main.
Im compiling some code at runtime then loading the assembly into the current appdomain, however when i then try to do Type.GetType it cant find the type...
Here is how i compile the code...
public static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = false;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
compilerparams.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{
// this happens for dynamic assemblies, so just ignore it.
}
}
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
{
AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
return results.CompiledAssembly;
}
}
This bit fails after getting the type from the compiled assembly just fine, it does not seem to be able to find it using Type.GetType....
Assembly assem = RuntimeCodeCompiler.CompileCode(code);
string typeName =
String.Format("Peverel.AppFramework.Web.GenCode.ObjectDataSourceProxy_{0}",
safeTypeName);
Type t = assem.GetType(typeName); //This works just fine..
Type doesntWork = Type.GetType(t.AssemblyQualifiedName);
Type doesntWork2 = Type.GetType(t.Name);
....
Found this nice bit of code that ensures no matter how you load your assembly it is always available from Type.GetType.
My class for compiling code into the current appdomain now looks like :
public static class RuntimeCodeCompiler
{
private static volatile Dictionary<string, Assembly> cache = new Dictionary<string, Assembly>();
private static object syncRoot = new object();
static Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();
static RuntimeCodeCompiler()
{
AppDomain.CurrentDomain.AssemblyLoad += (sender, e) =>
{
assemblies[e.LoadedAssembly.FullName] = e.LoadedAssembly;
};
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
{
Assembly assembly = null;
assemblies.TryGetValue(e.Name, out assembly);
return assembly;
};
}
public static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = false;
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
string location = assembly.Location;
if (!String.IsNullOrEmpty(location))
{
compilerparams.ReferencedAssemblies.Add(location);
}
}
catch (NotSupportedException)
{
// this happens for dynamic assemblies, so just ignore it.
}
}
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
{
AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
return results.CompiledAssembly;
}
}
public static Assembly CompileCodeOrGetFromCache(string code, string key)
{
bool exists = cache.ContainsKey(key);
if (!exists)
{
lock (syncRoot)
{
exists = cache.ContainsKey(key);
if (!exists)
{
cache.Add(key, CompileCode(code));
}
}
}
return cache[key];
}
}
You should read a bit more about assembly loading, type resolution, ... I don't know exactly why your code works at all, but I guess you have the following problem:
You compile the assembly and then you call AppDomain.CurrentDomain.Load to load the assembly. But you do not return the assembly you have just loaded. You return the assembly from the compilation result. Now you have two instances of the same assembly and you have each type from that assembly twice. These pairs have the same names, but they are not the same types!