实现C#即时编译器

结合控制台重定向和C#即使编译器(见我上面两篇文章)写的WinForm即时C#编译器,功能还不错。
文本框就是你Main方法内的语句,可以输入任意测试代码,支持错误行号定位,编译结果捕获,自动拆分窗格等,程序按F5执行,F5…… 忘记在代码里面加说明了:( 时间不早了,上传睡觉,带批处理build代码和SharpDevelop方式源代码哦。

可以拿下面的代码测试程序

//F5: Compile and Run the app    F6:Kill current Running App
//-----------------------------------------------------------
System.Diagnostics.Process.Start("notepad");

//test Generic Collection
List<int> lstInt = new List<int>{
    1,3,5,7,9,11
};
foreach(var v in lstInt)
    Console.WriteLine(v);

//test Timer
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate{
    System.Console.WriteLine(DateTime.Now.TimeOfDay.ToString());
};
timer.Start();
Console.ReadKey();

//test WinForm Application
//Application.Run(new Form());

这个程序用了我两天的时间,涉及到技术有:
1、同线程的控制台重定向到文本框
2、不同线程的控制台重定向到文本框-异步方式
3、编译代码并执行(Invoke方式和Process方式)
4、结束进程树
5、文件操作等

实现编译器的代码如下:

//#define CompileIntoMemory

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace PhoenixCompiler
{
    /// <summary>
    
/// director the Console output to ListBox
    
/// in MainForm Construction: 
    
/// </summary>
    public class PhoenixWriter : System.IO.TextWriter
    {
        delegate void VoidAction();
        System.Windows.Forms.TextBox txtBox;
        
        public PhoenixWriter(System.Windows.Forms.TextBox box)
        {
            this.txtBox = box;
        }
        
        public override System.Text.Encoding Encoding {
            get {    return System.Text.Encoding.UTF8;}
        }
        
        //here, must use parameter: char value
        public override void Write(char value)
        {
            VoidAction action = delegate{
                txtBox.AppendText(value.ToString());
            };
            txtBox.BeginInvoke(action);
        }
    }
    
    
    
    /// <summary>
    
/// Description of PhoenixCompiler.
    
/// </summary>
    public class PhoenixCompiler
    {
        public PhoenixCompiler()
        {
        }
        
        public string GenerateCode(string userCode)
        {
            string namespaces =@"using System;
using System.ComponentModel;
using System.Text;using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms
;using System.Threading;
using System.Reflection;
";
            string codeHead = @"
sealed class Phoenix
{
    public static void Main()
    {
//----------your code here-----------
";
        //userCode here
            string codeTail = @"
//----------your code here-----------
    }
}
";
            string compileCodes = namespaces + codeHead + userCode + codeTail;
            return compileCodes;
        }
        
        public CompilerResults Compile(string codes)
        {
            //CSharpCodeProvider
            System.CodeDom.Compiler.CodeDomProvider compiler = new Microsoft.CSharp.CSharpCodeProvider();
            //CompilerParameters
            System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
            parameters.WarningLevel = 4;
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");    
            #if CompileIntoMemory
            parameters.GenerateInMemory = true;
            #else
            parameters.GenerateExecutable=true;
            #endif        
            return compiler.CompileAssemblyFromSource(parameters,codes);
    
        }        
}
    
    
    /// <summary>
    
/// Description of MainForm.
    
/// </summary>
    public partial class MainForm : Form
    {
        System.Diagnostics.Process process;
        
        public MainForm()
        {
            InitializeComponent();
            //redirector Console output to ListBox lstResult
            Console.SetOut(new PhoenixWriter(txtResult));
        }
        
        //KillProcessTreeById
        public void KillProcessTreeById(int parentId)
        {
            //find all the process id created by parentId, Saved it to List childIds
            System.Collections.Generic.List<int> childIds=
                new System.Collections.Generic.List<int>();
            System.Diagnostics.Process[] processes =
                System.Diagnostics.Process.GetProcesses();
            foreach (var element in processes) {
                string path = string.Format("win32_process.handle='{0}'",element.Id);
                using (var mo= new System.Management.ManagementObject(path)) {
                    try {
                        mo.Get();
                    } catch (System.Management.ManagementException me) {
                        throw me;
                    }
                    int id=Convert.ToInt32(mo["ParentProcessId"]);
                    if (id==parentId) {
                        childIds.Add(element.Id);
                    }
                }    
            }
            
            foreach (var element in childIds) {
                //Console.WriteLine(element);
                System.Diagnostics.Process processKill = 
                    System.Diagnostics.Process.GetProcessById(element);
                if (processKill.ProcessName !="conhost") {
                    processKill.Kill();
                }
                //processKill.CloseMainWindow();
                
//processKill.Close();
            }
            var processParent = System.Diagnostics.Process.GetProcessById(parentId);
            if (processParent !=null) {
                processParent.Kill();
            }
        }
        
        void TxtCodeKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {//F5:116        e.KeyCode.ToString() + ":" + e.KeyValue.ToString();
            if (e.KeyValue == 116) {
                if (process!=null) {
                    this.KillProcessTreeById(process.Id);
                    process=null;
                }
                PhoenixCompiler compiler = new PhoenixCompiler();
                string code = compiler.GenerateCode(txtCode.Text);
                System.CodeDom.Compiler.CompilerResults result = compiler.Compile(code);
                ShowResult(result);
            }
            if (e.KeyValue==117) {//F6:117 here should terminate the process tree ... ...
                if (process != null) {
                    this.KillProcessTreeById(process.Id);
                    process=null;
                }
            }
        }
        
        public void ShowResult(System.CodeDom.Compiler.CompilerResults result)
        {
            txtResult.Text="";
            Console.WriteLine("Phoenix Compiler! \r\n\tCopyright by XUMINGHUI(2013)");
            Console.WriteLine("-----------------------------------------------\n");
            if (result.Errors.HasErrors) {
                Console.WriteLine("Build ERROR:\r\n");
                foreach (System.CodeDom.Compiler.CompilerError error in result.Errors) {
                    Console.WriteLine(error.Line + ":" + error.ErrorText);
                }
                return;
            }
            //build OK
            Console.WriteLine("Build Successfully:\r\n");
            
            try {//call Main entry, Console output --> WinForm Control
                #if CompileIntoMemory
                Type Phoenix = result.CompiledAssembly.GetType("Phoenix");
                Phoenix.GetMethod("Main").Invoke(null,new string[]{});
                #else    //start another thread to run the generated application
                System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo{
                    FileName=result.PathToAssembly,
                    UseShellExecute=false,
                    CreateNoWindow=true,
                    RedirectStandardError=true,
                    RedirectStandardOutput=true
                };
                process = new System.Diagnostics.Process();
                process.OutputDataReceived +=(s,e)=>{
                    if (e.Data!=null) {
                        Console.WriteLine(e.Data);
                    }
                };
                process.ErrorDataReceived +=(s,e)=>{
                    if (e.Data!=null) {
                        Console.WriteLine(e.Data);
                    }
                };
                process.StartInfo = info;
                process.EnableRaisingEvents = true;
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                #endif
            } catch (System.Reflection.TargetInvocationException ex) {
                Console.WriteLine("Exception:" + ex.InnerException.Message);
            }
        }            

        
        void MainFormFormClosing(object sender, FormClosingEventArgs e)
        {
            if (process != null) {
                    this.KillProcessTreeById(process.Id);
                    process=null;
            }
        }
        
        
        void TxtResultDoubleClick(object sender, EventArgs e)
        {
            if (txtResult.Text=="") {
                return;
            }
            string path = System.IO.Path.GetTempFileName();
            System.IO.File.AppendAllText(path,txtResult.Text);
            System.Diagnostics.Process.Start("notepad",path);
        }

        void TxtCodeDoubleClick(object sender, EventArgs e)
        {
            PhoenixCompiler compiler = new PhoenixCompiler();
            string code = compiler.GenerateCode(txtCode.Text);
            string path = System.IO.Path.GetTempFileName();
            System.IO.File.AppendAllText(path,code);
            System.Diagnostics.Process.Start("notepad",path);
        }
    }
}

 

原文地址:https://www.cnblogs.com/flaaash/p/3084881.html