繁体   English   中英

“在运行时编译C#代码时,非静态字段,方法或属性需要对象引用。”

[英]“An object reference is required for the non-static field, method or property.” while compiling C# code at runtime

我有一个公共类“ CodeCompiler”,它使我可以在运行时编译和运行C#代码。 就像IDE一样。

当我单击“ button1”时,它将在运行时创建代码,进行编译和执行。

我的主Form1包含一个名为“ textbox1”的TextBox控件。 为了在运行时对“ textbox1”进行更改,我创建了这个button1_Click事件。 但是当我单击它时,它显示了一个运行时错误...

Compiler Errors :
Line 14,34    : An object reference is required for the non-static field, method, or property 'Compiling_CSharp_Code_at_Runtime.Form1.textBox1'

它显示了我何时编辑“ textbox1”上的文本数据。 但是,如果我尝试对其他属性(例如“大小”,“位置”)进行更改,那么请想象会发生什么!

 using System;
 using System.Text;
 using Microsoft.CSharp;
 using System.CodeDom.Compiler;
 using System.Reflection;

 namespace Compiling_CSharp_Code_at_Runtime
 {
     public class CodeCompiler
     {
        public CodeCompiler()
        {
        }

        public object ExecuteCode(string code, string namespacename, string classname,
                                  string functionname, bool isstatic,
                                  string[] References1, params object[] args)
        {
            object returnval = null;
            CompilerParameters compilerparams = new CompilerParameters();
            for (int i = 0; i <= References1.GetUpperBound(0); i++)
            {
                compilerparams.ReferencedAssemblies.Add(References1[i]);
            }
            Assembly asm = BuildAssembly(code, compilerparams);
            object instance = null;
            Type type = null;
            if (isstatic)
            {
                type = asm.GetType(namespacename + "." + classname);
            }
            else
            {
                instance = asm.CreateInstance(namespacename + "." + classname);
                type = instance.GetType();
            }
            MethodInfo method = type.GetMethod(functionname);
            returnval = method.Invoke(instance, args);
            return returnval;
        }

        private Assembly BuildAssembly(string code, CompilerParameters compilerparams)
        {
            Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            compilerparams.GenerateExecutable = false;
            compilerparams.GenerateInMemory = true;
            CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
            if (results.Errors.HasErrors)
            {
                StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
                foreach (CompilerError error in results.Errors )
                {
                    errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
                }
                throw new Exception(errors.ToString());
            }
            else
            {
                return results.CompiledAssembly;
            }
        }
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CodeCompiler cc = new CodeCompiler();
            string SourceCode1 = @"
                using Compiling_CSharp_Code_at_Runtime;
                using System;
                using System.ComponentModel;
                using System.Windows.Forms;
                using System.Drawing;
                namespace N1
                {
                    public class C1
                    {
                        public static void F1(string st1, string st2)
                        {
                            Compiling_CSharp_Code_at_Runtime.Form1.textBox1.Text += ""This is a DEMO   "" st1 + st2.ToUpper();
                        }
                    }
                }";
            string namespace1 = "N1", class1 = "C1", function1 = "F1";
            bool IsStatic = true;
            object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic, new string[] { "Compiling CSharp Code at Runtime.exe", "System.Windows.Forms.dll", "System.Drawing.dll", "System.ComponentModel.dll", "System.dll" }, "arg1", "arg2");
        }
    }
}

我在这个建议为的站点上发现了许多与此问题相关的问题:

“看来我正在从静态方法中调用非静态属性。我应该使该属性成为静态属性,或者创建Form1的实例。”

但是,即使在运行时创建Form1实例也很困难!

问题似乎是您根本没有将要在其上执行代码的Form1引用传递给CodeCompiler 您在Form1中调用它的事实不会更改任何内容-对象不会自动使用它们学习有关该对象的任何信息。 (如果这样做的话,事情将会复杂得多。)

您访问Form1方式也不正确-您正在使用类型名(顺便说一句,它是毫无意义的完全限定路径,因为类C1Form1不在同一个命名空间中,但您要包含Form1 '通过using )来引用已编译代码中的s命名空间,以引用该类型的非静态成员。 该实例成员textBox1类型Form1只能从一些实例来访问,但有访问Form1 对象不符合逻辑的方式。 如果您实例化了10个该怎么办? 如何决定在这10个电话中,哪一个返回您的通话?

如果您想继续沿着这条道路走,应该做些什么(我不确定为什么要在C#中模仿eval()),您将放弃很多使C#变得简单易用的安全性(可以使用)传递给您想要在CodeCompiler的构造函数或ExecuteCode方法中更改的Form1实例的引用。 我认为后者可能更有意义。

您应该更改SourceCode1使其看起来像这样(这也可以修复原始代码中的错字,恢复丢失的+字符):

string SourceCode1 = @"
    using Compiling_CSharp_Code_at_Runtime;
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Drawing;
    namespace N1
    {
        public class C1
        {
            public static void F1(string st1, string st2, Form1 formToExecuteOn)
            {
                formToExecuteOn.textBox1.Text +=
                    ""This is a DEMO   "" + st1 + st2.ToUpper();
            }
        }
    }";

然后像这样调用ExecuteCode()方法:

object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic,
    new string[] { "Compiling CSharp Code at Runtime.exe",
    "System.Windows.Forms.dll", "System.Drawing.dll",
    "System.ComponentModel.dll", "System.dll" },
    "arg1", "arg2", this);

这将编译代码,以便要使用的Form1实例在调用时可以传递给该方法。 在实际上为方法调用传递的参数列表(即最后一个参数this )中提供了对该Form1实例的引用。

当然,即使可行,它也只允许您在Form1对象上执行代码。 更大的一点是,如果您要走这条路,则需要将对您想要以某种方式更改的任何内容的引用传递给CodeCompiler 我不知道对象是否objectToChange反而会工作的formToChange ,多少信息,编译器将需要约你传递,以在其上执行代码的对象。

再说一次,感觉:您需要一个非常非常独特的用例,以使其中的任何一个都可以很好地利用时间或理智。 (您每次想运行任何东西 ,都必须将七个精确构造的对象(主要是字符串)传递给ExecuteCode() !)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM