C# 编译用户提供的代码并使用

本文关键字:代码 编译 用户 | 更新日期: 2023-09-27 17:56:29

我要做的是允许用户在文本框中编写方法并让我的代码调用该方法。这最终将用于演示小程序,以便在给定目标函数的情况下进行优化。

所以我一直在使用一个示例控制台应用程序,但我遇到了问题。我已经检查了堆栈溢出和代码项目以及其他来源,并且已经到了可以编译代码的地步。但是我不知道如何调用它,只能访问一种方法。

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。如果这不可行,我会在这一点上采取我能得到的。

任何帮助或指导将不胜感激。谢谢。

C# 编译用户提供的代码并使用

您需要

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();
        }
    }
}