CSharpCodeProvider: referencing other generated "InMemory" assembl

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I'm using the CSharpCodeProvider to buils some assemblies @ runtime which are
never saved as files (cp.GenerateInMemory = true;).
The generated assemblies are hierachically dependent on each other so I
generate the "bottom" assemblies first.

How do I add a dependency to another previously loaded (generated) assembly?

I would be happy if CompilerParameters.ReferencedAssemblies.Add could take a
System.Reflection.Assembly reference as parameter.

A possible solution would be to generate dll files and reference them but I
like the idea of not having any files to cleanup when my application exits.

Any suggestions appreciated.
/Jan
 
Jan said:
I'm using the CSharpCodeProvider to buils some assemblies @ runtime
which are never saved as files (cp.GenerateInMemory = true;).
The generated assemblies are hierachically dependent on each other so
I generate the "bottom" assemblies first.

How do I add a dependency to another previously loaded (generated)
assembly?

I would be happy if CompilerParameters.ReferencedAssemblies.Add could
take a System.Reflection.Assembly reference as parameter.

A possible solution would be to generate dll files and reference them
but I like the idea of not having any files to cleanup when my
application exits.

Because you're not saving them to disk, why not build a single
assembly?

FB


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
Good point. I have earlier been using that solution but as I didn't mention
the application/system can build more assemblies while executing some already
builded ones.
 
I believe this does everything you need it to excuse the sloppy code ... I
will put up a blog post later today about it and post link here.

using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace ConsoleApplication9
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{


class Program {
static void GenerateMainAssembly() {
Microsoft.CSharp.CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("inmemoryassembly.dll");

parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class MyObject {";
source += " public void Test() {";
source += " System.Console.WriteLine(\"Test\");";
source += " OtherObject.SomeMethod();";
source += " System.Console.ReadLine();";
source += " }";
source += "}";

CompilerResults results = compiler.CompileAssemblyFromSource(parameters,
source);
//call test
object o = results.CompiledAssembly.CreateInstance("MyObject");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("Test");
mi.Invoke(o, null);

}

private static void CheckResults(CompilerResults Results) {
if(Results.Errors.Count > 0) {
throw new System.Exception("Compile Failed");
}
}

static void GenerateOtherAssembly() {
CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");

parameters.OutputAssembly = "inmemoryassembly.dll";
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class OtherObject {";
source += " public static void SomeMethod() {";
source += " System.Console.WriteLine(\"foo\");";
source += " }";
source += "}";

CompilerResults results = compiler.CompileAssemblyFromSource(parameters,
source);
CheckResults(results);
}
static void Main(string[] args) {
GenerateOtherAssembly();
GenerateMainAssembly();
}
}
}
}
 
Blog Post : http://geekswithblogs.net/gyoung/archive/2006/04/27/76533.aspx

Cheers,

Greg
Greg Young said:
I believe this does everything you need it to excuse the sloppy code ... I
will put up a blog post later today about it and post link here.

using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace ConsoleApplication9
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{


class Program {
static void GenerateMainAssembly() {
Microsoft.CSharp.CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("inmemoryassembly.dll");

parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class MyObject {";
source += " public void Test() {";
source += " System.Console.WriteLine(\"Test\");";
source += " OtherObject.SomeMethod();";
source += " System.Console.ReadLine();";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
//call test
object o = results.CompiledAssembly.CreateInstance("MyObject");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("Test");
mi.Invoke(o, null);

}

private static void CheckResults(CompilerResults Results) {
if(Results.Errors.Count > 0) {
throw new System.Exception("Compile Failed");
}
}

static void GenerateOtherAssembly() {
CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");

parameters.OutputAssembly = "inmemoryassembly.dll";
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class OtherObject {";
source += " public static void SomeMethod() {";
source += " System.Console.WriteLine(\"foo\");";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
CheckResults(results);
}
static void Main(string[] args) {
GenerateOtherAssembly();
GenerateMainAssembly();
}
}
}
}





Jan said:
I'm using the CSharpCodeProvider to buils some assemblies @ runtime which
are
never saved as files (cp.GenerateInMemory = true;).
The generated assemblies are hierachically dependent on each other so I
generate the "bottom" assemblies first.

How do I add a dependency to another previously loaded (generated)
assembly?

I would be happy if CompilerParameters.ReferencedAssemblies.Add could
take a
System.Reflection.Assembly reference as parameter.

A possible solution would be to generate dll files and reference them but
I
like the idea of not having any files to cleanup when my application
exits.

Any suggestions appreciated.
/Jan
 
if you have a huge amount of dynamic code you would be unable to lazy load
it and the initial compile would be extremely slow.
 
Thanks alot.

<Comment posted in Greg's blog>

/Jan

Greg Young said:
Blog Post : http://geekswithblogs.net/gyoung/archive/2006/04/27/76533.aspx

Cheers,

Greg
Greg Young said:
I believe this does everything you need it to excuse the sloppy code ... I
will put up a blog post later today about it and post link here.

using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace ConsoleApplication9
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{


class Program {
static void GenerateMainAssembly() {
Microsoft.CSharp.CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("inmemoryassembly.dll");

parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class MyObject {";
source += " public void Test() {";
source += " System.Console.WriteLine(\"Test\");";
source += " OtherObject.SomeMethod();";
source += " System.Console.ReadLine();";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
//call test
object o = results.CompiledAssembly.CreateInstance("MyObject");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("Test");
mi.Invoke(o, null);

}

private static void CheckResults(CompilerResults Results) {
if(Results.Errors.Count > 0) {
throw new System.Exception("Compile Failed");
}
}

static void GenerateOtherAssembly() {
CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");

parameters.OutputAssembly = "inmemoryassembly.dll";
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class OtherObject {";
source += " public static void SomeMethod() {";
source += " System.Console.WriteLine(\"foo\");";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
CheckResults(results);
}
static void Main(string[] args) {
GenerateOtherAssembly();
GenerateMainAssembly();
}
}
}
}





Jan said:
I'm using the CSharpCodeProvider to buils some assemblies @ runtime which
are
never saved as files (cp.GenerateInMemory = true;).
The generated assemblies are hierachically dependent on each other so I
generate the "bottom" assemblies first.

How do I add a dependency to another previously loaded (generated)
assembly?

I would be happy if CompilerParameters.ReferencedAssemblies.Add could
take a
System.Reflection.Assembly reference as parameter.

A possible solution would be to generate dll files and reference them but
I
like the idea of not having any files to cleanup when my application
exits.

Any suggestions appreciated.
/Jan
 
I tried the using the generated name to no avail seems to only work with an
assigned name.

Cheers,

Greg
Jan said:
Thanks alot.

<Comment posted in Greg's blog>

/Jan

Greg Young said:
Blog Post :
http://geekswithblogs.net/gyoung/archive/2006/04/27/76533.aspx

Cheers,

Greg
Greg Young said:
I believe this does everything you need it to excuse the sloppy code ...
I
will put up a blog post later today about it and post link here.

using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace ConsoleApplication9
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{


class Program {
static void GenerateMainAssembly() {
Microsoft.CSharp.CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("inmemoryassembly.dll");

parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class MyObject {";
source += " public void Test() {";
source += " System.Console.WriteLine(\"Test\");";
source += " OtherObject.SomeMethod();";
source += " System.Console.ReadLine();";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
//call test
object o = results.CompiledAssembly.CreateInstance("MyObject");
Type t = o.GetType();
MethodInfo mi = t.GetMethod("Test");
mi.Invoke(o, null);

}

private static void CheckResults(CompilerResults Results) {
if(Results.Errors.Count > 0) {
throw new System.Exception("Compile Failed");
}
}

static void GenerateOtherAssembly() {
CSharpCodeProvider codeProvider = new
Microsoft.CSharp.CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();

CompilerParameters parameters = new CompilerParameters(new string[]
{"mscorlib.dll"});

parameters.ReferencedAssemblies.Add("System.dll");

parameters.OutputAssembly = "inmemoryassembly.dll";
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;

string source = "";
source += "public class OtherObject {";
source += " public static void SomeMethod() {";
source += " System.Console.WriteLine(\"foo\");";
source += " }";
source += "}";

CompilerResults results =
compiler.CompileAssemblyFromSource(parameters, source);
CheckResults(results);
}
static void Main(string[] args) {
GenerateOtherAssembly();
GenerateMainAssembly();
}
}
}
}





I'm using the CSharpCodeProvider to buils some assemblies @ runtime
which
are
never saved as files (cp.GenerateInMemory = true;).
The generated assemblies are hierachically dependent on each other so
I
generate the "bottom" assemblies first.

How do I add a dependency to another previously loaded (generated)
assembly?

I would be happy if CompilerParameters.ReferencedAssemblies.Add could
take a
System.Reflection.Assembly reference as parameter.

A possible solution would be to generate dll files and reference them
but
I
like the idea of not having any files to cleanup when my application
exits.

Any suggestions appreciated.
/Jan
 
OK. Good tip.

I expect my final application would be generating way under 100 assemblies
at its peak scenario.
My application converts some user-written script-files into C# and then
builds them to execute the code so it's really up to my customers/users how
deep the hierarcy will be and how many files they have in a single "project".

I hope my concept holds.

Cheers
 
Greg said:
if you have a huge amount of dynamic code you would be unable to lazy
load it and the initial compile would be extremely slow.

Any dynamic compiled assembly is already in your appdomain anyway
(unless compiled in a separate appdomain), and because they're
in-memory, there's no lazy loading required, as they're already loaded.

So I don't see why this is relevant. (but perhaps I missed something)

FB


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
Lets say I have 100000 lines of code I want to dynamically compile in my
application.

I can either put them all into 1 assembly as you mention and pay the full
cost up front or I can break the code up into multiple assemblies.

I can immediately load my core assemblies and wait until the code is
actually needed to compile/load the other code. It is quite common in fact
to have dynamic code which is _not_ used very often, as such it generally
makes sense to compile it (and pay the memory overhead of the assembly) only
when you actually need the functionality.

I had a perfect example of this in an app I wrote some time ago. It allowed
the user to create external scripts to do various things in the application
and it could then load/run these scripts (the scripts were in fact mucked
into a plugin interface behind the scenes). A user could quite easily have
the scripts for 5000 of these plugins in their setup but only actually have
5 configured for use. As such I would lazy load the plugins compiling them
as needed.

Cheers,

Greg
 
Greg said:
Lets say I have 100000 lines of code I want to dynamically compile in
my application.

I can either put them all into 1 assembly as you mention and pay the
full cost up front or I can break the code up into multiple
assemblies.

yes, but that's only true if you compile the assemblies in app A and
load them in app B. THe topic here was in-memory compilation, which
means that you will have the compiled assemblies in your appdomain
already. If you compile 10 or 100 assemblies or 1, it doesn't matter,
they're already in your appdomain.

If you're suggesting to postpone generation and compilation till you
actually need it (thus generate code later on and compile it then),
then you have a point, but it has nothing to do with assembly load, as
all are already in-memory, in-process if you compile up front.
I can immediately load my core assemblies and wait until the code is
actually needed to compile/load the other code. It is quite common in
fact to have dynamic code which is not used very often, as such it
generally makes sense to compile it (and pay the memory overhead of
the assembly) only when you actually need the functionality.
I had a perfect example of this in an app I wrote some time ago. It
allowed the user to create external scripts to do various things in
the application and it could then load/run these scripts (the scripts
were in fact mucked into a plugin interface behind the scenes). A
user could quite easily have the scripts for 5000 of these plugins in
their setup but only actually have 5 configured for use. As such I
would lazy load the plugins compiling them as needed.

Ok, but that's something else than compile up front into 10 assemblies
because you want to load only 1 of them and 9 maybe later on. If you
compile 10 assemblies at time T, you WILL have 10 assemblies in your
appdomain already, so every time you compile code into multiple
assemblies at the same time is not worth the effort.

FB
Cheers,

Greg

lazy >> load it and the initial compile would be extremely slow.
Any dynamic compiled assembly is already in your appdomain anyway
(unless compiled in a separate appdomain), and because they're
in-memory, there's no lazy loading required, as they're already
loaded.

So I don't see why this is relevant. (but perhaps I missed
something)

FB
runtime >> >> which are never saved as files (cp.GenerateInMemory =
true;). >> >> The generated assemblies are hierachically dependent
on each other >> so >> I generate the "bottom" assemblies first.


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
Back
Top