簡體   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