c# - 编译和执行单行代码

标签 c# compiler-construction compiler-errors

我正在为一个项目创建一个/kind of/自定义编译器。我正在做的是让用户在文本框中输入代码行,或者他们可以从文本文件中导入一些代码。

最近几天我一直在尝试对此进行测试,但没有结果。我有一个名为 Pressure 的类,其中有一个名为“emit”的公共(public)方法,它只显示一个文本框,就像这样......

public void emit()
{
    MessageBox.Show("HOORA!");
}

我有一个名为“testCompile.txt”的文本文件,如下所示:
PressureTransducer pt = new PressureTransducer(0,0);
pt.emit();

当插入到 VS 中时,它编译得很好,因为它应该。之后,我尝试像这样编译文件......
String sourceName = @"C:\Users\Devic\Desktop\CompileTester\testCompile.txt";

CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = true;
//cp.OutputAssembly = null;
cp.GenerateInMemory = true;
cp.TreatWarningsAsErrors = false;
CompilerResults cr = provider.CompileAssemblyFromFile(cp,
        sourceName);
if (cr.Errors.Count > 0)
{
    // Display compilation errors.
    Console.WriteLine("Errors building {0} into {1}",
        sourceName, cr.PathToAssembly);
    foreach (CompilerError ce in cr.Errors)
    {
        Console.WriteLine("  {0}", ce.ToString());
        Console.WriteLine();
    }
}
else
{
    // Display a successful compilation message.
    Console.WriteLine("Source {0} built into {1} successfully.",
        sourceName, cr.PathToAssembly);
}

但是VS给了我错误:

c:\Users\Devic\Desktop\CompileTester\testCompile.txt(1,29) : error CS1518: Expected class, delegate, enum, interface, or struct

The thread 0x1290 has exited with code 0 (0x0).



关于发生了什么的任何想法?

最佳答案

您需要将文本文件中的代码封装到可用的类和方法中。

下面是我使用了几年的代码,它允许 C# 脚本在我的应用程序中运行,它甚至可以传入用户定义的变量。我在我的代码中传递了其他参数,以让脚本编写者可以完全访问其他现有的类实例,但我删除了这些参数,因为它们是我的软件所独有的。如果您想提供对应用程序中任何现有类或表单的访问权限,您也可以这样做。

使用您的类(class)PressureTransducer您需要确保正确引用了声明该类型的 DLL,并且命名空间包含在 Fake 代码封装的 using 部分中。但是,我有一个内置部分来自动引用您正在运行的程序当前引用的所有程序集,因此通常会自动处理所有事情。

此外,这将代码作为源代码的字符串并将程序集生成到内存中,因此没有磁盘访问 - 它运行得非常快。

注意:这里使用了一个过时的函数,codeProvider.CreateCompiler(); ,但它仍然为我工作。不过,我可能最终应该更新它。

private static object RunCSharpCode(string CSharpCode, bool ShowErrors, string StringParameter)
{
    try
    {
        #region Encapsulate Code into a single Method
        string Code =
            "using System;" + Environment.NewLine +
            "using System.Windows.Forms;" + Environment.NewLine +
            "using System.IO;" + Environment.NewLine +
            "using System.Text;" + Environment.NewLine +
            "using System.Collections;" + Environment.NewLine +
            "using System.Data.SqlClient;" + Environment.NewLine +
            "using System.Data;" + Environment.NewLine +
            "using System.Linq;" + Environment.NewLine +
            "using System.ComponentModel;" + Environment.NewLine +
            "using System.Diagnostics;" + Environment.NewLine +
            "using System.Drawing;" + Environment.NewLine +
            "using System.Runtime.Serialization;" + Environment.NewLine +
            "using System.Runtime.Serialization.Formatters.Binary;" + Environment.NewLine +
            "using System.Xml;" + Environment.NewLine +
            "using System.Reflection;" + Environment.NewLine +

            "public class UserClass" + Environment.NewLine +
            "{" + Environment.NewLine +
            "public object UserMethod( string StringParameter )" + Environment.NewLine +
            "{" + Environment.NewLine +
            "object Result = null;" + Environment.NewLine +
            Environment.NewLine +
            Environment.NewLine +

            CSharpCode +

            Environment.NewLine +
            Environment.NewLine +
            "return Result;" + Environment.NewLine +
            "}" + Environment.NewLine +
            "}";
        #endregion

        #region Compile the Dll to Memory

        #region Make Reference List
        Assembly[] FullAssemblyList = AppDomain.CurrentDomain.GetAssemblies();

        System.Collections.Specialized.StringCollection ReferencedAssemblies_sc = new System.Collections.Specialized.StringCollection();

        foreach (Assembly ThisAssebly in FullAssemblyList)
        {
            try
            {
                if (ThisAssebly is System.Reflection.Emit.AssemblyBuilder)
                {
                    // Skip dynamic assemblies
                    continue;
                }

                ReferencedAssemblies_sc.Add(ThisAssebly.Location);
            }
            catch (NotSupportedException)
            {
                // Skip other dynamic assemblies
                continue;
            }
        }

        string[] ReferencedAssemblies = new string[ReferencedAssemblies_sc.Count];
        ReferencedAssemblies_sc.CopyTo(ReferencedAssemblies, 0);
        #endregion

        Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
        System.CodeDom.Compiler.ICodeCompiler CSharpCompiler = codeProvider.CreateCompiler();
        System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters(ReferencedAssemblies);
        parameters.GenerateExecutable = false;
        parameters.GenerateInMemory = true;
        parameters.IncludeDebugInformation = false;
        parameters.OutputAssembly = "ScreenFunction";

        System.CodeDom.Compiler.CompilerResults CompileResult = CSharpCompiler.CompileAssemblyFromSource(parameters, Code);
        #endregion

        if (CompileResult.Errors.HasErrors == false)
        { // Successful Compile
            #region Run "UserMethod" from "UserClass"
            System.Type UserClass = CompileResult.CompiledAssembly.GetType("UserClass");
            object Instance = Activator.CreateInstance(UserClass, false);
            return UserClass.GetMethod("UserMethod").Invoke(Instance, new object[] { StringParameter });
            #endregion
        }
        else // Failed Compile
        {
            if (ShowErrors)
            {
                #region Show Errors
                StringBuilder ErrorText = new StringBuilder();

                foreach (System.CodeDom.Compiler.CompilerError Error in CompileResult.Errors)
                {
                    ErrorText.Append("Line " + (Error.Line - 1) +
                        " (" + Error.ErrorText + ")" +
                        Environment.NewLine);
                }

                MessageBox.Show(ErrorText.ToString());
                #endregion

            }
        }
    }
    catch (Exception E)
    {
        if (ShowErrors)
            MessageBox.Show(E.ToString());
    }

    return null;
}

关于c# - 编译和执行单行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34388459/

相关文章:

c++ - C & C++ 中 sizeof() 运算符的返回值

编译器不显示任何错误或警告,但程序不工作

C# 2 数组拆分量问题

c# - 使用 Database.SqlQuery() 的 Entity Framework ,其中列名是无效的 C# 成员名称

c# - MVC : Pagination hindering the way a list is sorted

c# - 如何在CMD中使用SET和COPY?

c - 生成的 Bison 解析器的意外行为

Delphi编译器警告指向Delphi自己的单元

asp.net - 解决方案中未包含的Visual Studio编译文件

java - Java Swing GUI错误