You certainly can store the code in database, but running it will be way more difficult. To run code dynamically, you need to compile it, which is quite possible through CodeDOM. It actually works through regular C# compiler, and this compiler is always bundled with all versions of .NET and run by CodeDOM.
Now, this is how the problem looks like:
You cannot compile one expression. The minimal code you can have is one class with one method. You don't have to store it all in the database, but I suggest that a stored code would be a whole function, otherwise it's hard go make the code compile, validate it, etc. You can develop a system which implements some interface, and the stored function would be implementation. On top of that, you can add some pre-created code to this implementation, so the stored function will be inserted in it. However, you can store whole C# file, which is a bit easier.
Now, you should have code which compiles this C# file in memory, shows compile-time error, etc. Second phase would be checking up if the required interface is implemented. Using Reflection, you can do that and also create the object of a class implementing the interface and invoke it and return the result of calculation.
Now, will it be a surprise for you: what I just described was the easiest part! Now we're getting to a difficult part:
You cannot do it in the same application domain as the one of your main program. Here is why: the compiled assembly will be loaded in this application domain, but
.NET does not allow unloading of any assemblies, for some really good reasons. You can only unload a whole process or Application Domain, nothing else. So, there is one solution: compile your assembly in memory in a separate Application Domain. When you need to compile another assembly, you will unload that Application Domain and create a new one, as this is the only way to unload dynamically compiled assembly. But now, remember that the Application Domains are well isolated, as well as separate processes. What does it mean to you? It means that you will have a problem calling the compiled method, because you need to pass parameter values to it and return the value. You will have to do it through the boundary between Application Domain, so it will require Inter-Process Communications (IPC). To simplify this, the class
System.AppDomain
already has simplified IPC facilities in it. In particular, you can use
System.AppDomain.DoCallback
. See:
http://msdn.microsoft.com/en-us/library/system.appdomain.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.appdomain.docallback.aspx[
^].
I described related problems and some architectural skeletons in my past solutions. Please see:
Create WPF Application that uses Reloadable Plugins...[
^],
AppDomain refuses to load an assembly[
^],
code generating using CodeDom[
^],
Create WPF Application that uses Reloadable Plugins...[
^] (this one is the closest to your problem).
There are some alternatives:
1) Compile assembly into an executable file, a console application with command line interface and returning value either via
ExitCode
or in a text form, output onto console. A parent application can run it using
System.Diagnostics.Process.Run
and re-direct the console output.
See:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx[
^] (here you will find a sample of re-direction).
For command line parser, you can you use my work published in CodeProject:
Enumeration-based Command Line Utility[
^] — this library is quite convenient and easy to use.
2) Develop a fully-fledged parser from some simple language. The result of parsing should be an expression tree capable of substitution of some primitive-type values and evaluation of expression. I mean it: your stored expressions will not be in C#, but is some simplistic language which would allow to parse and evaluate single expressions. You will probably able to use some available code for this.
So, now think about it all and decide is you really want to get into all this.
—SA