C〓〓のダイナミックコンパイル、ボタンの機能の動態的な配置を実現します.

26227 ワード

今はやっているシステムに対してもっと柔軟にして、機能配置がますます便利になり、一部の効率を犠牲にして、システムの柔軟性を交換して、メンテナンス、機能拡張アップグレードなどの仕事に対してとても便利になりました.
先日、一つの項目は画面上のボタンが全部配置可能で、位置と機能は全部配置可能です.位置はいいです.xmlでいいです.しかし、機能の配置はちょっと難しいです.インターフェースを使うとパラメータが設定しにくいし、インターフェースを使っても、実際に呼び出した時にはどのクラスが実装されているかを明確にしなければなりません.反射を使うということもありますが、これは確かにいい方法です.でもやはり呼び出し時にはパラメータが不確定で反射も無駄です.長い間調べましたが、やはり動的コンパイルを選択しました.
専門のクラスを使って、動的コンパイルのプロセスを完成します.実はこの動的コンパイルは、動的にコードを生成し、動的にコンパイルして、直接にシステムで使用できます.コードに機能を追加するために必要なダイナミックリンクライブラリ、プログラムセット、名前空間が必要です.以下は私が使っているダイナミックコンパイルのクラスです.
using System;
using System.Data;
using System.Configuration;
using System.IO;
using System.Text;
using System.CodeDom.Compiler;
using System.Windows.Forms;
using Microsoft.CSharp;
using System.Reflection;

namespace DynamicAddFunction
{
    /// <summary>   
    ///                   ,             。
    /// </summary>   
    public class Evaluator
    {
        private string filepath = Path.Combine(Application.StartupPath, "FunBtn.config");
     
        #region     
        /// <summary>   
        ///             
        /// </summary>   
        /// <param name="items">   
        ///            
        /// </param>   
        public Evaluator(EvaluatorItem[] items)
        {
            ConstructEvaluator(items);      //                  
        }
        /// <summary>   
        ///             
        /// </summary>   
        /// <param name="returnType">     </param>   
        /// <param name="expression">     </param>   
        /// <param name="name">       </param>   
        public Evaluator(Type returnType, string expression, string name)
        {
            //             
            EvaluatorItem[] items = { new EvaluatorItem(returnType, expression, name) };
            ConstructEvaluator(items);      //               
        }
        /// <summary>   
        ///             
        /// </summary>   
        /// <param name="item">       </param>   
        public Evaluator(EvaluatorItem item)
        {
            EvaluatorItem[] items = { item };//                      
            ConstructEvaluator(items);      //                  
        }
        /// <summary>   
        ///             
        /// </summary>   
        /// <param name="items">        </param>   
        private void ConstructEvaluator(EvaluatorItem[] items)
        {
            //  C#        
            //ICodeCompiler comp = (new CSharpCodeProvider().CreateCompiler());
            CSharpCodeProvider comp = new CSharpCodeProvider(); 
            //           
            CompilerParameters cp = new CompilerParameters();

            Configer configer = Configer.Current(filepath);
            string[] assemblies = configer.GetAssembly("FunBtn//assembly//dll","name");
            cp.ReferencedAssemblies.AddRange(assemblies);           //       
            //cp.ReferencedAssemblies.Add("system.dll");              //      system.dll       
            //cp.ReferencedAssemblies.Add("system.data.dll");         //      system.data.dll       
            //cp.ReferencedAssemblies.Add("system.xml.dll");          //      system.xml.dll       
            //cp.ReferencedAssemblies.Add("system.windows.forms.dll");
            //cp.ReferencedAssemblies.Add("FunButton.dll");
            //cp.ReferencedAssemblies.Add("DynamicAddFunction.exe");
            cp.GenerateExecutable = false;                          //           
            cp.GenerateInMemory = true;                             //         

            StringBuilder code = new StringBuilder();               //        
            /* 
             *               
             */
            //         
            string[] usings = configer.GetAssembly("FunBtn//assembly//using", "name");

            foreach (var @using in usings)
            {
                code.Append(@using+"
");// } //code.Append("using System;
"); //code.Append("using System.Data;
"); //code.Append("using System.Data.SqlClient;
"); //code.Append("using System.Data.OleDb;
"); //code.Append("using System.Xml;
"); //code.Append("using FunButton;
"); //code.Append("using System.Windows.Forms;
"); //code.Append("using DynamicAddFunction;
"); code.Append("namespace EvalGuy {
"); // EvalGuy, code.Append(" public class _Evaluator {
"); // _Evaluator , foreach (EvaluatorItem item in items) // { code.AppendFormat(" public {0} {1}() ", // item.ReturnType.Name.ToLower() , // item.Name); // code.Append("{ "); // if (item.ReturnType.Name == "Void") { code.AppendFormat("{0};", item.Expression);// , } else { code.AppendFormat("return ({0});", item.Expression);// , } code.Append("}
"); // } code.Append("} }"); // // CompilerResults cr = comp.CompileAssemblyFromSource(cp, code.ToString()); if (cr.Errors.HasErrors) // { StringBuilder error = new StringBuilder(); // error.Append(" : "); // foreach (CompilerError err in cr.Errors) // { error.AppendFormat("{0}
", err.ErrorText); // , } throw new Exception(" : " + error.ToString());// } Assembly a = cr.CompiledAssembly; // _Compiled = a.CreateInstance("EvalGuy._Evaluator"); // EvalGuy._Evaluator } #endregion #region /// <summary> /// /// </summary> /// <param name="name"> </param> /// <returns> </returns> public int EvaluateInt(string name) { return (int)Evaluate(name); } /// <summary> /// /// </summary> /// <param name="name"> </param> /// <returns> </returns> public string EvaluateString(string name) { return (string)Evaluate(name); } /// <summary> /// /// </summary> /// <param name="name"> </param> /// <returns> </returns> public bool EvaluateBool(string name) { return (bool)Evaluate(name); } /// <summary> /// object /// </summary> /// <param name="name"> </param> /// <returns> </returns> public object Evaluate(string name) { MethodInfo mi = _Compiled.GetType().GetMethod(name);// _Compiled name return mi.Invoke(_Compiled, null); // mi } public void EvaluateVoid(string name) { MethodInfo mi = _Compiled.GetType().GetMethod(name);// _Compiled name mi.Invoke(_Compiled, null); // mi } #endregion #region /// <summary> /// /// </summary> /// <param name="code"> </param> /// <returns> </returns> static public int EvaluateToInteger(string code) { Evaluator eval = new Evaluator(typeof(int), code, staticMethodName);// Evaluator return (int)eval.Evaluate(staticMethodName); // } /// <summary> /// /// </summary> /// <param name="code"> </param> /// <returns> </returns> static public string EvaluateToString(string code) { Evaluator eval = new Evaluator(typeof(string), code, staticMethodName);// Evaluator return (string)eval.Evaluate(staticMethodName); // } /// <summary> /// /// </summary> /// <param name="code"> </param> /// <returns> </returns> static public bool EvaluateToBool(string code) { Evaluator eval = new Evaluator(typeof(bool), code, staticMethodName);// Evaluator return (bool)eval.Evaluate(staticMethodName); // } /// <summary> /// object /// </summary> /// <param name="code"> </param> /// <returns> </returns> static public object EvaluateToObject(string code) { Evaluator eval = new Evaluator(typeof(object), code, staticMethodName);// Evaluator return eval.Evaluate(staticMethodName); // object } /// <summary> /// void /// </summary> /// <param name="code"> </param> static public void EvaluateToVoid(string code) { Evaluator eval = new Evaluator(typeof(void), code, staticMethodName);// Evaluator eval.EvaluateVoid(staticMethodName); // object } #endregion #region /// <summary> /// /// </summary> private const string staticMethodName = "ExecuteBtnCommand"; /// <summary> /// , /// </summary> object _Compiled = null; #endregion } /// <summary> /// ( ) /// </summary> public class EvaluatorItem { /// <summary> /// /// </summary> public Type ReturnType; /// <summary> /// /// </summary> public string Expression; /// <summary> /// /// </summary> public string Name; /// <summary> /// /// </summary> /// <param name="returnType"> </param> /// <param name="expression"> </param> /// <param name="name"> </param> public EvaluatorItem(Type returnType, string expression, string name) { ReturnType = returnType; Expression = expression; Name = name; } } }
その柔軟性を向上させるために、上のクラスに追加されたプログラムセットと名前空間、および呼び出し機能のコードは、xmlフォーマットを読み込むプロファイルに変更されて取得されます.理論的には、任意の.netで作成したdllやexeなどの機能をシステムに追加することができます.システムの柔軟性を大幅に強化しました.
プロファイルを読み書きするクラスは一例モードを採用しており、システムに対する消費を減らすことができます.コードは以下の通りです.
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Reflection;
using System.Configuration;

namespace DynamicAddFunction
{
    ///   <summary> 
    ///               , app.config   。 
    ///   </summary> 
    public class Configer
    {
        #region       

        private string version; //   
        private string updatetime; //    
        private string isautoupdate; //      
        private string funbtnwidth; //       
        private string funbtnheight; //       
        private string expandbtnwidth; //       
        private string expandbtnheight; //       

        //private string btnname; //    
        //private string btntext; //      
        //private string btntype; //    
        //private string btnleft; //   
        //private string btntop; //   
        //private string btnreturntype; //     
        //private string btncode; //    

        private string arrange; //       
        private string firstleft; //         
        private string firsttop; //         
        private string horizontal; //    
        private string vertical; //    

        private string filePath; //    
        private static Configer current; //    

        #endregion

        /// <summary>
        ///          ,         , Current          
        /// </summary>
        /// <param name="filepath">  Url</param>
        private Configer(string filepath)
        {
            this.filePath = filepath;
        }

        /// <summary>
        ///       。
        /// </summary>
        /// <param name="filepath">      </param>
        /// <returns>      </returns>
        public static Configer Current(string filepath)
        {
            if (current == null)
            {
                current = new Configer(filepath);
            }
            //current = new Configer(filepath);
            return current;
        }       

        /// <summary>
        ///                 
        /// </summary>
        /// <param name="path">  </param>
        /// <param name="nodeProperty">   </param>
        public string[] GetAssembly(string path, string nodeProperty)
        {
            if (!File.Exists(filePath)) return null;
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            string[] assemblies = null;

            //      
            XmlNodeList nodelist = xmlDoc.SelectNodes(path);
            if (nodelist != null)
            {
                //      ,     ,       dll  
                assemblies = new string[nodelist.Count];

                for (int i = 0; i < nodelist.Count; i++)//    
                {
                    var element = (XmlElement)nodelist[i];
                    assemblies[i] = element.GetAttribute(nodeProperty);//  dll    
                }
            }
            return assemblies;//    
        }

        /// <summary>                                                                         
        ///       
        /// </summary>
        /// <param name="path">    </param>
        /// <param name="nodeProperty">    </param>
        /// <returns>   </returns>
        public string GetNodeProperty(string path, string nodeProperty)
        {
            XmlDocument doc = new XmlDocument();
            //    
            doc.Load(filePath);

            XmlElement element = null;

            //    
            element = (XmlElement)(doc.SelectSingleNode(path));

            if (element != null)
            {
                return element.GetAttribute(nodeProperty);
            }
            else
            {
                return " ";
            }
        }

        /// <summary> 
        ///      
        /// </summary> 
        /// <param name="path">    </param>
        /// <param   name= "nodeProperty">     </param>
        /// <param   name= "nodeValue">   </param> 
        public void SetNodeProperty(string path, string nodeProperty, string nodeValue)
        {
            var doc = new XmlDocument();
            //    
            doc.Load(filePath);

            XmlElement element = null;

            //      
            element = (XmlElement)(doc.SelectSingleNode(path));

            if (element != null)
            {
                //        
                element.SetAttribute(nodeProperty, nodeValue);
            }
            doc.Save(filePath);
        }

        /// <summary>
        ///       
        /// </summary>
        /// <param name="path">    </param>
        /// <param name="nodeProperty">    </param>
        /// <returns>   </returns>
        public string GetNodeValue(string path, string nodeProperty)
        {
            XmlDocument doc = new XmlDocument();
            //    
            doc.Load(filePath);

            XmlNode node = null;

            //    
            node = (doc.SelectSingleNode(path));

            if (node != null)
            {
                //      
                return node.Value;
            }
            else
            {
                return " ";
            }
        }

        /// <summary> 
        ///      
        /// </summary> 
        /// <param name="path">    </param>
        /// <param   name= "nodeProperty">     </param>
        /// <param   name= "nodeValue">   </param> 
        public void SetNodeValue(string path, string nodeProperty, string nodeValue)
        {
            var doc = new XmlDocument();
            //    
            doc.Load(filePath);

            XmlNode node = null;

            //    
            node = (doc.SelectSingleNode(path));

            if (node != null)
            {
                //        
                node.Value = nodeValue;
            }
            doc.Save(filePath);
        }


        /// <summary>
        ///                 
        /// </summary>
        /// <param name="path">  </param>
        /// <param name="nodeProperty">   </param>
        /// <param name="nodeValue">   </param>
        public void SetAllNodeProperty(string path, string nodeProperty, string nodeValue)
        {
            if (!File.Exists(filePath)) return;
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            //      
            var selectSingleNode = xmlDoc.SelectNodes(path);
            if (selectSingleNode != null)
            {
                XmlNodeList nodelist = selectSingleNode;

                foreach (var VARIABLE in nodelist)//    
                {
                    XmlElement element = (XmlElement)VARIABLE;
                    //((XmlElement)VARIABLE).Attributes[nodeProperty].Value = nodeValue;
                    element.SetAttribute(nodeProperty, nodeValue);
                }
            }
            xmlDoc.Save(filePath);
        }

        /// <summary>
        ///     
        /// </summary>
        /// <param name="path">     </param>
        /// <param name="name">    </param>
        /// <param name="nodeProperties">    </param>
        /// <param name="nodeValues">     </param>
        public void CreateNode(string path,string name, string[] nodeProperties, string[] nodeValues)
        {
            if (!File.Exists(filePath)) return;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            //        
            var selectSingleNode = xmlDoc.SelectSingleNode(path);
            if (selectSingleNode != null)
            {
                XmlElement xmlElement = xmlDoc.CreateElement(name);

                //      ,    
                for (int i = 0; i < nodeProperties.Length; i++)
                {
                    //    
                    xmlElement.SetAttribute(nodeProperties[i], nodeValues[i]);
                }
                selectSingleNode.AppendChild(xmlElement);
            }
            xmlDoc.Save(filePath);//  
        }


        /// <summary>
        ///     
        /// </summary>
        /// <param name="path">     </param>
        /// <param name="name">     </param>
        public void RemoveNode(string path,string name)
        {
            if (!File.Exists(filePath)) return;
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(filePath);

            //     
            var selectSingleNode = xmlDoc.SelectSingleNode(path);
            if (selectSingleNode != null)
            {
                //     
                var node=selectSingleNode.SelectSingleNode(name);

                if (node != null)
                {
                    selectSingleNode.RemoveChild(node);
                }
            }
            xmlDoc.Save(filePath);//  
        }
    }
}
プロファイルの情報は以下の通りです.FunBtn.sofig
<?xml version="1.0" encoding="utf-8"?>
<FunBtn>
  <!--      -->
  <info version="1.00" updatetime="2013-01-01 10:00:00.123" isautoupdate="true" />
  <!--             -->
  <assembly>
    <dll name="system.dll" />
    <dll name="system.data.dll" />
    <dll name="system.xml.dll" />
    <dll name="system.windows.forms.dll" />
    <dll name="FunButton.dll" />
    <dll name="DynamicAddFunction.exe" />
    <using name="using System;" />
    <using name="using System.Data;" />
    <using name="using System.Data.SqlClient;" />
    <using name="using System.Data.OleDb;" />
    <using name="using System.Xml;" />
    <using name="using FunButton;" />
    <using name="using System.Windows.Forms;" />
    <using name="using DynamicAddFunction;" />
  </assembly>
  <!--         -->
  <btndetail>
    <btn name="btnDelOrder" value="    " type="funbtn" rank="0" left="10" top="5" returntype="void" code="new DelOrderBtn().DelOrder(Form1.objs)" />
    <btn name="btnCheckOut" value="   " type="funbtn" rank="-1" left="10" top="335" returntype="void" code="new CheckOutBtn().CheckOut(Form1.objs)" />
    <btn name="btnClose" value="  " type="funbtn" rank="-1" left="240" top="335" returntype="void" code="Application.Exit()" />
    <btn name="btnDelAllOrder" value="    " type="funbtn" rank="-1" left="240" top="225" returntype="void" code="new DelOrderBtn().DelOrder(Form1.objs)" />
    <btn name="btnMore" value="   " type="funbtn" rank="6" left="10" top="230" returntype="void" code="new frmMore().Show()" />
  </btndetail>
</FunBtn>
このようにシステムの呼び出し時に便利になります.(ここのすべてのボタンはそれぞれのイベント、すなわちButtonuClickイベントです.それらはnameを通して構成ファイルの中に対応するコードを見つけて、動的にコンパイルして実行します.)
        /// <summary>
        ///           
        /// </summary>
        public void Button_Click(object sender, EventArgs e)
        {
            try
            {
                Configer configer = Configer.Current(filePath);

                //       
                string code = configer.GetNodeProperty(
                    "FunBtn//btndetail//btn[@name='" + ((Button)sender).Name + "']", "code");
                
                //            
                string returnType =
                    configer.GetNodeProperty("FunBtn//btndetail//btn[@name='" + ((Button)sender).Name + "']",
                                             "returntype");
                //       ,             
                switch (returnType)
                {
                    case "void":
                        Evaluator.EvaluateToVoid(code);
                        break;
                    case "object":
                        Evaluator.EvaluateToObject(code);
                        break;
                    case "int":
                        Evaluator.EvaluateToInteger(code);
                        break;
                    case "bool":
                        Evaluator.EvaluateToBool(code);
                        break;
                    case "string":
                        Evaluator.EvaluateToString(code);
                        break;
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }
このように、設定ファイルにプログラムセットと名前付きコントロールが追加されている限り、コードOKは任意のdllを呼び出すことができます.拡張機能が強いことを意味します.追加機能については、新しいバージョンを再発行しなくてもいいです.直接に使用するdllをプログラムのルートディレクトリに入れて、正しいFunBtn.co figを配置すればいいです.
もちろん、実はダイナミックコンパイルは勧めません.効率に影響しますから.ボタンを押すたびに、再度動的コンパイルが必要です.効率は必ず下がります.参考にする時は、慎重に選択してください.