C# Компиляция предоставленного пользователем кода и использование
Я пытаюсь разрешить пользователю писать метод в текстовом поле, и мой код вызывает этот метод. В конечном итоге это будет использовано в демонстрационном апплете для оптимизации с учетом целевой функции.
Итак, я работал с образцом консольного приложения, но у меня возникли проблемы. Я проверил переполнение стека, кодпроект и другие источники и дошел до того, что смог скомпилировать код. Но я теряюсь в том, как вызвать его и получить доступ только к методу.
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();
}
}
}
Я пробовал разные комбинации того, как вызывать Invoke для этого метода и получать ошибки. Я хочу, чтобы пользователь мог определить функцию, подобную этой:
public double funcname(double x, double y)
{
return x+y;
}
И тогда я мог бы просто вызвать funcname напрямую. Если это невозможно, я возьму то, что смогу получить в этот момент.
Любая помощь или руководство будут оценены. Благодарю.
2 ответа
Вам нужно включить пространство имен в GetType
вызов.
(Или удалите пространство имен из источника)
Вы можете предпочесть позвонить GetTypes()
и увидеть все типы, определенные в сборке.
Я полагаю, что эта статья поможет вам получить доступ к методу напрямую через интерфейсы http://www.codeproject.com/Articles/26312/Dynamic-Code-Integration-with-CodeDom
Возможно, нижеприведенное не относится непосредственно к вашему запросу, но я считаю, что вам нужно использовать Activator для создания экземпляра класса, чтобы вы могли вызвать testd
Я имею в виду, что у вашего кода нет объекта, только определение класса.
Также я использовал GetTypes()[0]
так как GetType()
не работал для меня
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();
}
}
}