C # Compilant du code fourni par l'utilisateur et en utilisant
-
12-11-2019 - |
Question
Ce que j'essaie de faire, c'est permettre à un utilisateur d'écrire une méthode dans une zone de texte et de faire appeler cette méthode. Cela sera finalement utilisé dans une applet de démonstration pour l'optimisation compte tenu d'une fonction d'objectif.
J'ai donc travaillé avec un exemple d'application de console mais j'ai des problèmes. J'ai vérifié Stack Overflow et CodeProject et d'autres sources, et j'ai atteint le point où je peux compiler le code. Mais je suis perdu sur la façon de l'appeler et d'accès uniquement à une méthode.
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();
}
}
}
J'ai essayé différentes combinaisons sur la façon d'appeler l'invocation sur la méthode et de continuer à obtenir des erreurs. Ce que je veux pouvoir faire, c'est que l'utilisateur définisse une fonction comme ceci:
public double funcname(double x, double y)
{
return x+y;
}
Et puis je pourrais simplement appeler Funcname directement. Si ce n'est pas faisable, je vais prendre ce que je peux obtenir à ce stade.
Toute aide ou guidage serait appréciée. Merci.
La solution
Vous devez inclure l'espace de noms dans le GetType
appel.
(Ou supprimer l'espace de noms de la source)
Vous préférez peut-être appeler GetTypes()
et voir tous les types définis dans l'assemblage à la place.
Autres conseils
Je crois que cet article vous aidera à accéder directement à la méthode en utilisant des interfaceshttp://www.codeproject.com/articles/26312/dynamic-code-integration-with-codedom
Peut-être que ce qui précède n'est pas pertinent directement pour votre demande, mais je pense que vous devez utiliser Activator pour créer une instance de la classe afin que vous puissiez appeler le testd
Méthode Je veux dire que votre code défini n'a pas d'objet, juste une définition de classe.
J'ai aussi utilisé GetTypes()[0]
car GetType()
n'a pas fonctionné pour moi
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();
}
}
}