实现C#即时编译器

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

实现C#即时编译器_第1张图片

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

 

// 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);
        }
    }
}

 

 

你可能感兴趣的:(实现C#即时编译器)