Compiling and replacing classes at runtime in C#

Started by
12 comments, last by Ens 15 years, 10 months ago
Quote:Original post by Umbrae
I asked a very similar question: Edit and continue.
A resource I found useful was: Shadow Copying Assemblies.


I was wondering how you used the shadowcopying.

I did a spike of loading the script assembly in a separate AppDomain. This separate AppDomain has shadowcopying turned on. This part works just fine. I can write to the generated assembly again.
The problem however is that the calling assembly/application also wants to load the script assembly and thus locks the assembly file. The reason it does this is to provide reflection over the objects in the new AppDomain. That makes perfect sense, but it means that the script assembly is loaded in the script AppDomain as well as in the main AppDomain, so I can't unload it anymore from the main AppDomain.

This is turning out to be quite a pain. Compiling the script and loading it is easy as pie. Having a compiler built in the .NET framework is great.
But unloading/reloading assemblies is quite a hassle because the calling assembly also loads the script assembly.
STOP THE PLANET!! I WANT TO GET OFF!!
Advertisement
Quote:Original post by Structural
I was wondering how you used the shadowcopying..

I didn't get far enough to use it, so I guess I would be in the same boat as you.

If you do find out (and likewise if I find out) let everyone know, I'm sure it's useful information.
Quote:Original post by Umbrae
Quote:Original post by Structural
I was wondering how you used the shadowcopying..

I didn't get far enough to use it, so I guess I would be in the same boat as you.

If you do find out (and likewise if I find out) let everyone know, I'm sure it's useful information.


I found a hint: scriptAppDomain.Load() will indeed force the assembly to be loaded in the current appdomain.

You could create a shared "ScriptEngine" assembly, and invoke Assembly.Load() through a remote call on the script appDomain. The script engine assembly will be locked, but that won't be an issue as the actual script will be in yet another assembly.

I think you could use Assembly.ReflectionOnlyLoad() to get reflection info hopefully without locking the assembly.
One thing that is still a blank more or less is how easy it'll be to invoke methods and getting members with only having reflection info.


So, to recap how to get around the locking of the assembly:

- create "Script Engine" assembly
- create script appDomain
- load script engine assembly in script's appdomain
- invoke a method in your script engine assembly and in the script appDomain to load your actual script assembly
- use Assembly.ReflectionOnlyLoad() to get reflection info of the script assembly (UNCERTAIN if this leaves the assembly file unlocked, MSDN doesn't state)
- somehow invoke methods and get members in the script appDomain

I'm going to try out the last two items. If that works I believe all bases are covered for using C# as a scripting language (the way I (think I) want it to work at least).

[edit]
Assembly.ReflectionOnlyLoad() DOES lock the file... buggery! A quick google seems to indicate there is no way around it.
This also means that anything you try to reflect the object will result in an attempt to load the assembly (reflection only or not) in the main appDomain. Even myScriptObject.GetType() from the main appDomain will.

One way to get around this may be to give the script engine an interface to invoke methods and get/set member variables and serialize/deserialze objects. But I don't feel it is viable to build all that for my personal project.

And another thing just hit me... even IF I can invoke script from the game, I still haven't figured out how to invoke game methods from script.
This poses an entirely new problem I think.

Right... I'm going to put this to rest now. This whole appDomain boundary stuff is giving me a headache.

If you figure it out Umbrae then let me know. I'm still hoping it is possible.
[/edit]

[Edited by - Structural on May 28, 2008 12:36:50 PM]
STOP THE PLANET!! I WANT TO GET OFF!!
Check out the "CLR Managed Debugger (mdbg) Sample". It might allow the edit and continue for your scripting. Also i have used IronPython rather successfully for a scripting language (linked to from the link below)

http://www.microsoft.com/downloads/details.aspx?FamilyID=38449a42-6b7a-4e28-80ce-c55645ab1310&displaylang=en


(edit-add:)
IronPython provided a very seamless and simple interface for scripting. No mucking around with loading assemblies or emitting IL. I could probably put together a working sample app with less than 15 lines of code to introduce scripting.

I created an entire scripting framework to handle and manage any number of different scripting engines simultaneously. The framework code weight is a meager 210 lines. The IronPython interface adds only 120 more AND of this only about 14 lines are actually dealing with IronPython - the rest of them are interactions with the framework.

Needless to say i have been very impressed with IronPython ;)

[Edited by - Ens on June 14, 2008 3:40:32 PM]

This topic is closed to new replies.

Advertisement