• 实现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);
            }
        }
    }

     

  • 相关阅读:
    利用书签栏作插入时失败告终
    组以逗号分隔的子串及跨平update join
    ms_sql:drop and create a job
    why dicePlayer cannot player with defy mb526
    好像国庆三天是可以加班工资计了
    msssql 用numberic(38)替代int去解决int不够的问题
    C#的switch与二维数组.....
    某牛人所留的联系方式
    封装对象类
    数据库访问小列题
  • 原文地址:https://www.cnblogs.com/flaaash/p/3084881.html
Copyright © 2020-2023  润新知