Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice to write highly user extendable C# application

I am currently at a research institute that does micromaching/fine mechanics and was asked to develop a controller software for the current setup we use in one of our labs.

We have a nano stage and some other equipment like shutters and filter wheels that should be controlled with a central application. The software provides pre-configured jobs for execution, which are basically algorithms that generate commands for the stage and are used to write different patterns with a laser into the samples (for example rectangles, cylinders, etc.)

Now it would be great to provide some kind of possibility to extend this list of predefined jobs on runtime, which means that algorithms like the ones provided can be added by the user.

I'm a C# newbie (and a Desktop application newbie in general) so I am extremely thankful if you can give me some hints on how this could be done or where I should start looking.

like image 342
user871784 Avatar asked Oct 26 '25 10:10

user871784


1 Answers

I did this 'script' thing using the .NET integrated C# compiler.
It is some work to do but basically is looks like this:

    public Assembly Compile(string[] source, string[] references) {
        CodeDomProvider provider = new CSharpCodeProvider();
        CompilerParameters cp = new CompilerParameters(references);
        cp.GenerateExecutable = false;
        cp.GenerateInMemory = true;
        cp.TreatWarningsAsErrors = false;

        try {
            CompilerResults res = provider.CompileAssemblyFromSource(cp, source);
            // ...
            return res.Errors.Count == 0 ? res.CompiledAssembly : null;
        }
        catch (Exception ex) {
            // ...
            return null;
        }
    }

    public object Execute(Assembly a, string className, string methodName) {
        Type t = a.GetType(className);
        if (t == null) throw new Exception("Type not found!");
        MethodInfo method = t.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);          // Get method
        if (method == null) throw new Exception("Method '" + methodName + "' not found!");                                  // Method not found

        object instance =  Activator.CreateInstance(t, this);
        object ret = method.Invoke(instance, null); 
        return ret;
    }

The real code does a lot more things, including a code editor.
It works very well for years now in our factory.

This way the users use C# for the scripts and can therefore use the same API as you do.

You can use a code template that looks like a plain .cs file. It is build at runtime and provided to the source parameter of Compile.

using System;
using System.IO;
using ...

namespace MyCompany.Stuff {
    public class ScriptClass {
        public object main() {

            // copy user code here
            // call your own methods here

        }

        // or copy user code here

        private int test(int x) { /* ... */ }
    }
}

Example:

string[] source = ??? // some code from TextBoxes, files or whatever, build with template file...
string[] references = new string[] { "A.dll", "B.dll" };

Assembly a = Compile(source, references);
object result = Execute(a, "MyCompany.Stuff.ScriptClass", "main");
like image 192
joe Avatar answered Oct 29 '25 00:10

joe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!