Add new cs files on the fly to load my application launcher?

I have a command handler that basically works like this:

ControlList.Handlers[CommandType.MyCommandComesHere].Handle(data);

      

Handlers

is Dictionary<CommandType, ICommandHandler>

, and CommandType

is an enumeration.

Handle

its rotation will lead to the following:

using System;
using log4net;

namespace My_Application
{
    public class MyCommand : ICommandHandler
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(MyCommand));

        public void Handle(Events data)
        {
            Console.WriteLine("I can load cs files on the fly yay!!");
        }
    }
}

      

My question is, how can I make my application compile and allow me to use this cs file while it is running?

Any simple example of this would be greatly appreciated but not required as long as I can get some guidance as to what I need to look for as I am not even sure if I need this to happen.

To put it simply, I am currently trying to figure out how to load the cs file into my application which is already compiled and currently running.

+3


source to share


2 answers


Using CodeDOM, you must first create a compiler provider . (You can set GenerateExecutable

on false

and GenerateInMemory

on true

for your own purposes.)

    var csc = new CSharpCodeProvider();
    var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
    parameters.GenerateExecutable = false;
    parameters.GenerateInMemory = true;

      

Then you can compile the assembly with CompileAssemblyFromSource

and return CompilerResults

from it. From this returned object, get a reference to the generated assembly using its property CompiledAssembly

.

    var results = csc.CompileAssemblyFromSource(parameters, "contents of the .cs file");
    var assembly = results.CompiledAssembly;

      

Then you can use reflection to instantiate from that assembly and call methods on them.

    var instance = assembly.CreateInstance("MyCommand");
    // etc...

      




Alternatively, if you are only interested in short snippets of code, you should probably use Roslyn . First you need to create ScriptEngine

.

var engine = new ScriptEngine();

      

Then you can just Execute

string on it - or Execute<T>

if you're sure the expression in the string returns the type being assigned T

.

var myObject = engine.Execute("1+1");
var myInt = engine.Execute<int>("1+1");

      

It's definitely more urgent, so it's worth checking out if it will serve your purpose.

+5


source


I was looking for different ways to achieve this goal and found the cs script library easy and handy. Here is the code snippet how I use it. It runs the cs code in the application domain, so it assumes the compiled cs script comes from a trusted source.



using CSScriptLibrary;
using csscript;
using System.CodeDom.Compiler;
using System.Reflection;

    //Method example - variable script contains cs code
    //This is used to compile cs to DLL and save DLL to a defined location
    public Assembly GetAssembly(string script, string assemblyFileName)
    {
        Assembly assembly;
        CSScript.CacheEnabled = true;            
        try
        {
            bool debugBuild = false;
#if DEBUG
            debugBuild = true;
#endif
            if (assemblyFileName == null)
                assembly = CSScript.LoadCode(script, null);
            else
                assembly = CSScript.LoadCode(script, assemblyFileName, debugBuild, null);
            return assembly;
        }
        catch (CompilerException e)
        {
            //Handle compiler exceptions
        }
    }

    /// <summary>
    /// Runs the code either form script text or precompiled DLL
    /// </summary>
    public void Run(string script)
    {
        try
        {
            string tmpPath = GetPathToDLLs();  //Path, where you store precompiled DLLs

            string assemblyFileName;
            Assembly assembly = null;
            if (Directory.Exists(tmpPath))
            {
                assemblyFileName = Path.Combine(tmpPath, GetExamScriptFileName(exam));
                if (File.Exists(assemblyFileName))
                {
                    try
                    {
                        assembly = Assembly.LoadFrom(assemblyFileName); //Načtení bez kompilace
                    }
                    catch (Exception exAssemblyLoad)
                    {
                        Tools.LogError(exAssemblyLoad.Message);
                        assembly = null;
                    }
                }
            }
            else
                assemblyFileName = null;

            //If assembly not found, compile it form script string
            if (assembly ==null) 
                assembly = GetAssembly(script, assemblyFileName);
            AsmHelper asmHelper = new AsmHelper(assembly);

            //This is how I use the compiled assembly - it depends on your actual code
            ICalculateScript calcScript = (ICalculateScript)asmHelper.CreateObject(GetExamScriptClassName(exam));
            cex = calcScript.Calculate(this, exam);
            Debug.Print("***** Calculated {0} ****", exam.ZV.ZkouskaVzorkuID);
        }
        catch (Exception e)
        {
            //handle exceptions
        }
    }

      

+1


source







All Articles