【问题标题】:How to compile code in C# Dot Net on run time?如何在运行时在 C# Dot Net 中编译代码?
【发布时间】:2017-04-30 10:09:02
【问题描述】:

所以我想编译一个包含 .cs 文件的整个文件夹,然后创建一个 DLL 文件,然后在运行时在我的项目中使用该 DLL。

我搜索了互联网,发现CSharpCodeProvider可以帮助我。

但让我感到困惑的是,这个网站上的大多数示例都展示了如何读取单个文件,而不是整个文件夹。

所以我假设包含.cs 文件的文件夹将链接在一起。 示例文件:

文件: TestMain.cs

class TestMain
    {
        public static void Main(string[] args)
        {
            Test t = new Test();
            t.Hello();
        }
    }

文件: Test.cs

public class Test
    {
        public void Hello()
        {
            Console.Write(@"Hello");
        }
    }

任何指导将不胜感激。

【问题讨论】:

  • 为什么要这样做?有什么原因吗?
  • 我和拉胡尔有同样的问题。这对我来说似乎是一个 XY 问题,你真正想要实现什么?
  • 好吧,我正在创建一个项目,它从文件夹中读取 .cs 文件并推断出没有类和方法变量等,并使用该信息来创建类图
  • 所以你只有一堆 .cs 文件,没有 csproj 文件?
  • 好吧,我只有 .cs 文件

标签: c# compilation


【解决方案1】:

好的,经过搜索和指导,这里是我的工作代码:

public static Assembly CompileAssembly(string[] sourceFiles, string outputAssemblyPath)
        {
            var codeProvider = new CSharpCodeProvider();

            var compilerParameters = new CompilerParameters
            {
                GenerateExecutable = false,
                GenerateInMemory = false,
                OutputAssembly = outputAssemblyPath
            };

            // Add CSharpSimpleScripting.exe as a reference to Scripts.dll to expose interfaces
            //compilerParameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);

            var result = codeProvider.CompileAssemblyFromFile(compilerParameters, sourceFiles); // Compile
            if (result.Errors.Count > 0)
            {
                MessageBox.Show(@"Error Occured");
            }
            else
            {
                return result.CompiledAssembly;

            }
            return null;
        }

【讨论】:

    【解决方案2】:

    基本上,您可以使用CodeDom.Compiler 来编译dll,我很久以前就写过类似的东西,然后使用Reflection 来动态引用它

    //dot net compiler
    using System; 
    using System.CodeDom.Compiler; 
    using System.IO; 
    
    namespace IndiLogix.dotCompiler 
    { 
        class dotCompiler 
        { 
            FileInfo sourceFile;// = new FileInfo(sourceName); 
            CodeDomProvider provider = null; 
            bool compileOk = false; 
    
    
            // Compile Executable 
            public bool CompileExecutable(String sourceName) 
            { 
                sourceFile = new FileInfo(sourceName); 
                I_GetProvider(sourceFile); 
                if (sourceFile.Extension.ToUpper(System.Globalization.CultureInfo.InvariantCulture) == ".CS") 
                { 
                    provider = CodeDomProvider.CreateProvider("CSharp"); 
                    //return "CSharp"; 
                } 
    
                if (provider != null) 
                { 
    
                    // Format the executable file name. 
                    // Build the output assembly path using the current directory 
                    // and _cs.exe or _vb.exe. 
    
                    String exeName = String.Format(@"{0}\{1}.exe", 
                    System.Environment.CurrentDirectory, 
                    sourceFile.Name.Replace(".", "_")); 
                    string dllName = String.Format(@"{0}\{1}.dll", System.Environment.CurrentDirectory, sourceFile.Name.Replace(".", "_")); 
    
                    CompilerParameters cp = new CompilerParameters(); 
    
                    // Generate an executable instead of a class library. 
                    cp.GenerateExecutable = true; 
    
                    // Specify the assembly file name to generate. 
                    cp.OutputAssembly = exeName; 
    
                    // Save the assembly as a physical file. 
                    cp.GenerateInMemory = false; 
    
                    // Set whether to treat all warnings as errors. 
                    cp.TreatWarningsAsErrors = false; 
    
                    // Invoke compilation of the source file. 
                    CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceName); 
                    string temp; 
                    if (cr.Errors.Count > 0) 
                    { 
                        // Display compilation errors. 
                        temp = sourceName + "\n" + cr.PathToAssembly; 
    
                        foreach (CompilerError ce in cr.Errors) 
                        { 
                            temp += "\nError:" + ce.ToString(); 
                        } 
                        System.Windows.Forms.MessageBox.Show(temp, "dotCompiler Error:", System.Windows.Forms.MessageBoxButtons.OK); 
                    } 
                    else 
                    { 
                        // Display a successful compilation message. 
                        //Console.WriteLine("Source {0} built into {1} successfully.",sourceName, cr.PathToAssembly); 
                        System.Windows.Forms.MessageBox.Show("Solution build sucessfully..\n\n" + sourceName + "\n" + cr.PathToAssembly,"dotCompiler:)",System.Windows.Forms.MessageBoxButtons.OK); 
                    } 
    
                    // Return the results of the compilation. 
                    if (cr.Errors.Count > 0) 
                    { 
                        compileOk = false; 
                    } 
                    else 
                    { 
                        compileOk = true; 
                    } 
                } 
                return compileOk; 
            } 
    
            private void I_GetProvider(FileInfo sourceFile) 
            { 
                // Select the code provider based on the input file extension. 
                if (sourceFile.Extension.ToUpper(System.Globalization.CultureInfo.InvariantCulture) == ".CS") 
                { 
                    provider = CodeDomProvider.CreateProvider("CSharp"); 
                } 
                else if (sourceFile.Extension.ToUpper(System.Globalization.CultureInfo.InvariantCulture) == ".VB") 
                { 
                    provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("VisualBasic"); 
                } 
                else 
                { 
                    //Console.WriteLine("Source file must have a .cs or .vb extension"); 
                    //_Notify("Error:", "Source file must have a .cs or .vb extension", ToolTipIcon.Error); 
                    System.Windows.Forms.MessageBox.Show( 
                    "Source file must have *.cs or *.vb extension", "dotCompiler Error", 
                    System.Windows.Forms.MessageBoxButtons.OK); 
                } 
            } 
    
            private string I_GetProvider_RetStr(FileInfo sourceFile) 
            { 
    
                // Select the code provider based on the input file extension. 
                if (sourceFile.Extension.ToUpper(System.Globalization.CultureInfo.InvariantCulture) == ".CS") 
                { 
                    provider = CodeDomProvider.CreateProvider("CSharp"); 
                    return "CSharp"; 
                } 
                else if (sourceFile.Extension.ToUpper(System.Globalization.CultureInfo.InvariantCulture) == ".VB") 
                { 
                    provider = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("VisualBasic"); 
                    return "VisualBasic"; 
                } 
                else 
                { 
                    //Console.WriteLine("Source file must have a .cs or .vb extension"); 
                    //_Notify("Error:", "Source file must have a .cs or .vb extension", ToolTipIcon.Error); 
                    return "Source file must have *.cs or *.vb extension"; 
                } 
            } 
    
            public bool CompileDll(String sourceName) 
            { 
    
                sourceFile = new FileInfo(sourceName); 
                I_GetProvider(sourceFile); 
    
                if (provider != null) 
                { 
    
                // Format the executable file name. 
                // Build the output assembly path using the current directory 
                // and _cs.exe or _vb.exe. 
    
                String exeName = String.Format(@"{0}\{1}.exe", 
                System.Environment.CurrentDirectory, 
                sourceFile.Name.Replace(".", "_")); 
                string dllName = String.Format(@"{0}\{1}.dll", System.Environment.CurrentDirectory, sourceFile.Name.Replace(".", "_")); 
    
                CompilerParameters cp = new CompilerParameters(); 
    
                // Generate an executable instead of a class library. 
                cp.GenerateExecutable = false; 
    
                // Specify the assembly file name to generate. 
                cp.OutputAssembly = dllName; 
    
                // Save the assembly as a physical file. 
                cp.GenerateInMemory = false; 
    
                // Set whether to treat all warnings as errors. 
                cp.TreatWarningsAsErrors = false; 
    
                // Invoke compilation of the source file. 
                CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceName); 
                string temp; 
                if (cr.Errors.Count > 0) 
                { 
                // Display compilation errors. 
                temp = "compiling " + sourceName + " to " + cr.PathToAssembly; 
    
                foreach (CompilerError ce in cr.Errors) 
                { 
                temp += "\nError:" + ce.ToString(); 
                } 
    
                    System.Windows.Forms.MessageBox.Show(temp, "dotCompiler Error:", System.Windows.Forms.MessageBoxButtons.OK); 
                } 
                else 
                { 
                    // Display a successful compilation message. 
                    //Console.WriteLine("Source {0} built into {1} successfully.",sourceName, cr.PathToAssembly); 
                    System.Windows.Forms.MessageBox.Show("Solution build sucessfully..\n\n" + sourceName + "\n" + cr.PathToAssembly, "dotCompiler:)", System.Windows.Forms.MessageBoxButtons.OK); 
                } 
    
                    // Return the results of the compilation. 
                    if (cr.Errors.Count > 0) 
                    { 
                        compileOk = false; 
                    } 
                    else 
                    { 
                        compileOk = true; 
                    } 
                } 
            return compileOk; 
            } 
    
        } 
    } 
    

    【讨论】:

    • 好吧,如果我没记错的话,你只是在编译一个文件。
    • 是的,它适用于单个文件,但有一个解决方法stackoverflow.com/questions/14502819/…
    • 我们将不胜感激提供示例代码。我还发现了这个资源link I found做检查和验证
    • @idenny 我不知道这里有什么要求,但您也可以查看 CS-Script csscript.net,它提供类似脚本的功能
    • @idenny 使用 CodeDomProvider.CompileAssemblyFromFile 方法可以指定多个文件,但我建议在源目录中使用 csc 作为 csc /out:mydll.dll *.cs 并使用反射来获取类和方法创建你的类图。
    【解决方案3】:
    string sourceCode = @"
        public class Test
        {
           public void Hello()
           {
              Console.Write(@'Hello');
           }
        }";
    
        var compParms = new CompilerParameters{
            GenerateExecutable = false, 
            GenerateInMemory = true
        };
    
        var csProvider = new CSharpCodeProvider();
        CompilerResults compilerResults = 
                csProvider.CompileAssemblyFromSource(compParms, sourceCode);
        object typeInstance = 
                compilerResults.CompiledAssembly.CreateInstance("Test");
        MethodInfo mi = typeInstance.GetType().GetMethod("Hello");
        mi.Invoke(typeInstance, null); 
        Console.ReadLine();
    

    【讨论】:

    • 我理解你的代码。但是如果我必须编译整个文件夹怎么办?
    • “编译文件夹”本身并不意味着任何东西。您的意思是单独编译每个 cs 文件还是创建单个 lerger 程序集?
    • 将具有相同名称空间的文件夹中的 .cs 文件编译成单个 DLL 文件,以后可以在运行时在我的项目中使用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多