简体   繁体   中英

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

I have a public class, "CodeCompiler", which allows me to compile and run C# code at run-time. Just like IDEs work.

When I click the "button1" it creates code at run-time, compiles and executes.

My main Form1 contains a TextBox control called "textbox1". In order to make changes on that "textbox1" by runtime I made this button1_Click event. But when I click it, it shows me a run-time error...

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'

It showed me when I was editing the text data on that "textbox1". But if I will try to make changes about other property like "Size", "Location" then imagine what will happen!

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

I found many problems related to this problem on this site where a suggestion was:

"It looks like I am calling a non static property from a static method. I should either make the property static, or create an instance of Form1."

But even creation an instance of Form1 was difficult at runtime!

The problem appears to be that you're not passing reference to the Form1 on which you want code to be executed to CodeCompiler at all. The fact that you're calling it within your Form1 doesn't change anything - objects don't automatically learn anything about the object using them. (If they did, things would be a lot more complicated.)

The way you're accessing Form1 is also incorrect - you're using the typename (by the way, as a fully-qualified path which is pointless, because while the class C1 is not in the same namespace as Form1 , you include Form1 's namespace in the compiled code via using ) to refer to a non-static member of the type. The instance member textBox1 of the type Form1 can be accessed only from some instance, but there's no logical way to access the Form1 object. What if you'd instantiated 10 of them? How would the decision be made which of those 10 to return to your call?

What you should do, if you want to continue down this path (and I'm not really sure why you're trying to mimic eval() in C# - you're throwing away a lot of the safety that makes C# nice and easy to work with), is pass a reference to the Form1 instance you want altered either in the constructor of CodeCompiler or in the ExecuteCode method. I think the latter would probably make more sense.

You should change your SourceCode1 so that it looks like this (this also fixes a typo in the original code, restoring a missing + character):

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

Then call the ExecuteCode() method like this:

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

This will compile the code such that the Form1 instance to be used can be passed to the method when it's invoked. And the reference to that Form1 instance is provided in the argument list that is actually passed for the method invocation (ie the last argument, this )..

Granted, even if that works, it'll only allow you to execute code on Form1 objects. The greater point of this is that if you're going to go down this path, you need to be passing reference to anything you want altered to CodeCompiler somehow. I'm not sure whether object objectToChange would work instead of formToChange , and how much information the compiler is going to need about the object you're passing in order to execute code on it.

And once more, for feeling: you need a very, very unique use case to make any of this even remotely a good use of time or sanity. (You have to pass seven precisely-constructed objects, mostly strings, to ExecuteCode() every single time you want to run anything!)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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