In C #, how do you refer to types from one assembly in memory inside another?

The example program below compiles two assemblies in memory. The first compilation works fine. The second is unsuccessful because it needs access to the class from the first assembly, and the type is not available.

In particular: the ReferencedAssemblies member of the CompilerParameters class is a collection of strings and is used to load the assembly manifest to get their types. It seems that the C # compiler gets types strictly from the manifest, and not through reflection (possibly for performance reasons). In any case, when the assembly is constructed in memory, there is no file and no manifest, therefore the second assembly fails with an error, for example:

COMPILER ERROR: metadata file 'ax5lw0tl, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null' could not be found

Adding an AssemblyResolver event handler does not work. I tried this and it looks like it is never called. From what I can say (and I'm new to .Net, so bear with me), the compiler only cares about the manifest; it actually does not try to load the assembly at this time, so the AssemblyResolver is not in the picture.

I could, if desperate, build my assemblies on disk that solve the immediate problem in order to have a physical dll and manifest for reading. I would rather not do this, as this leads to the need to manage what will become a very large collection of temporary assemblies on disk.

I am an .Net optimist can do this, and as a newbie, I just skipped it.

(Hopefully the space in the code looks fine. It seems to look right in the preview window for a few minutes, but once the syntax marker is done, it means the repeats and spacing are incorrect, although it remains readable.)

using System; using System.CodeDom.Compiler; using System.Reflection; using System.Collections.Generic; using Microsoft.CSharp; namespace AsmCompileTest { class Program { static Assembly Compile( string code, Assembly referencedAssembly ) { CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = false; cp.GenerateInMemory = true; if( null != referencedAssembly ) { cp.ReferencedAssemblies.Add( referencedAssembly.FullName ); } CodeDomProvider provider = new CSharpCodeProvider( new Dictionary<string,string> { { "CompilerVersion", "v3.5" } } ); CompilerResults compilerResults = provider.CompileAssemblyFromSource( cp, code ); if( compilerResults.Errors.HasErrors ) { foreach( CompilerError error in compilerResults.Errors ) { Console.WriteLine( "COMPILER ERROR: " + error.ErrorText ); } } return compilerResults.CompiledAssembly; } static string Code1 = "using System;" + "public class HelloClass" + " {" + " public HelloClass() { Console.WriteLine( \"Hello, World!\" ); }" + " }"; static string Code2 = "using System;" + "public class TestClass" + " {" + " public TestClass() { new HelloClass(); }" + " }"; static void Main() { Assembly asm1 = Compile( Code1, null ); Console.WriteLine( "Compiled: " + asm1.FullName ); asm1.GetType( "HelloClass" ).InvokeMember( String.Empty, BindingFlags.CreateInstance, null, null, null ); Assembly asm2 = Compile( Code2, asm1 ); Console.WriteLine( "Compiled: " + asm2.FullName ); asm2.GetType( "TestClass" ).InvokeMember( String.Empty, BindingFlags.CreateInstance, null, null, null ); } } } 
+4
source share
2 answers

Based on the documentation found on MSDN and on the code in the reflector I was looking at (for compiler classes), it is not possible to do what you want. The reason is that below, the code compiler classes that you use shell for the real compiler.

In addition, the code compiler classes actually generate temporary files below, and based on the code I looked in the reflector, they do not clear the files. Therefore, based on this, I would say, just create a file on disk in a temporary place, and then add a link to it.

+3
source

Define the interfaces in a regular assembly and suggest the classes in each generated assembly to implement these interfaces. Generated assemblies will need a link to the one that contains the interfaces, and not to each other.

+1
source

All Articles