C#: Vom Benutzer bereitgestellten Code kompilieren und verwenden
-
12-11-2019 - |
Frage
Was ich versuche, ist, einem Benutzer zu erlauben, eine Methode in ein Textfeld zu schreiben und meinen Code diese Methode aufrufen zu lassen.Dies wird schließlich in einem Demo-Applet zur Optimierung einer Zielfunktion verwendet.
Ich habe also mit einer Beispielkonsolenanwendung gearbeitet, habe aber Probleme.Ich habe Stack Overflow, Codeproject und andere Quellen überprüft und bin an dem Punkt angelangt, an dem ich den Code kompilieren kann.Aber ich weiß nicht, wie ich es aufrufe und nur auf eine Methode zugreife.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace CodeCompilerTest
{
class Program
{
static void Main(string[] args)
{
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
//parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
//parameters.OutputAssembly = "Output.dll";
string SourceString = @"
using System;
using System.Collections.Generic;
using System.Text;
namespace testone
{
public class myclass
{
public double Main()
{
return testd(5,8);
}
public double testd(double a, double b)
{
return a+b;
}
}
}";
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";");
}
Console.ReadLine();
}
Assembly mAssembly = results.CompiledAssembly;
Type scripttype = mAssembly.GetType("myclass");
Object rslt = new Object();
Object[] argin = {5, 8};
//rslt = scripttype.GetMethod("Main").Invoke(null, null);
rslt = scripttype.InvokeMember("Main", BindingFlags.InvokeMethod | BindingFlags.Public |BindingFlags.Static, null, null, null);
Console.WriteLine(((double)rslt).ToString());
Console.ReadLine();
}
}
}
Ich habe verschiedene Kombinationen zum Aufrufen von Invoke für die Methode ausprobiert und erhalte immer wieder Fehler.Ich möchte, dass der Benutzer eine Funktion wie diese definiert:
public double funcname(double x, double y)
{
return x+y;
}
Und dann könnte ich einfach funcname direkt aufrufen.Wenn dies nicht machbar ist, nehme ich, was ich an dieser Stelle bekommen kann.
Jede Hilfe oder Anleitung wäre dankbar.Danke.
Lösung
Sie müssen den Namespace in die einschließen GetType
Anruf.
(Oder entfernen Sie den Namespace aus der Quelle)
Vielleicht möchten Sie lieber anrufen GetTypes()
und sehen Sie stattdessen alle in der Assembly definierten Typen.
Andere Tipps
Ich glaube, dieser Artikel wird Ihnen dabei helfen, über Schnittstellen direkt auf die Methode zuzugreifenhttp://www.codeproject.com/Articles/26312/Dynamic-Code-Integration-with-CodeDom
Möglicherweise ist das Folgende nicht direkt für Ihre Anfrage relevant, aber ich glaube, dass Sie Activator verwenden müssen, um eine Instanz der Klasse zu erstellen, damit Sie die aufrufen können testd
Methode Ich meine, Ihr Code definiert ist kein Objekt, nur Klassendefinition.
Auch ich habe verwendet GetTypes()[0]
Weil GetType()
hat bei mir nicht funktioniert
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection;
namespace CodeCompilerTest
{
class Program
{
static void Main(string[] args)
{
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
//parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
//parameters.OutputAssembly = "Output.dll";
string SourceString = @"
using System;
using System.Collections.Generic;
using System.Text;
namespace testone
{
public class myclass
{
public double testd(double a, double b)
{
return a+b;
}
}
}";
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";");
}
Console.ReadLine();
}
Assembly mAssembly = results.CompiledAssembly;
Type scripttype = mAssembly.GetTypes()[0];
Object myObject = Activator.CreateInstance(scripttype);
double rsltd = 0.0;
Object[] argin = { 5.0, 8.0 };
rsltd =(double) scripttype.GetMethod("testd").Invoke(myObject,argin);
// object rslt = new object();
// rslt = scripttype.InvokeMember("testd", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null);
Console.WriteLine(rsltd.ToString());
Console.ReadLine();
}
}
}