C # Компиляция предоставленного пользователем кода и использование - PullRequest
1 голос
/ 12 мая 2011

Я пытаюсь разрешить пользователю писать метод в текстовом поле, и мой код вызывает этот метод. В конечном итоге это будет использоваться в демонстрационном апплете для оптимизации с учетом целевой функции.

Итак, я работал с образцом консольного приложения, но у меня возникли проблемы. Я проверил переполнение стека, кодпроект и другие источники и дошел до того, что смог скомпилировать код. Но я теряюсь в том, как вызвать его и получить доступ только к методу.

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 ]

1 голос
/ 29 октября 2012

Я полагаю, что эта статья поможет вам получить доступ к методу напрямую через интерфейсы 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();
        }
    }
}
1 голос
/ 12 мая 2011

Вам необходимо включить пространство имен в вызов GetType.
(Или удалите пространство имен из источника)

Вы можете предпочесть вызов GetTypes() и увидеть все типы, определенные в сборке.

...