Table of Contents

Strom zobrazující strukturu grafickým prvků našeho okna

Třída ReflectionModule zobrazuje typové informace ve stromu.

Hlavní okno zavolá konstruktor s parametrem TreeView a třemi dalšími tabulky pro zobrazení detailů.

       reflectionModule = new ReflectionModule (structureTree, propGrid, reflectionGrid, typeGrid);

Později z hlavního okna zavoláme funkci display, jako parametr předáme odkaz na hlavní okno

       reflectionModule.display (this);

Funkce display zavolá metodu addStructure

        private void addStructure (TreeNodeCollection target, object obj)
        {
           TreeNode node = new TreeNode ();
           node.Tag = obj;
           string typ = obj.GetType().ToString();
 
           if (obj is Control)
           {
              Control c = obj as Control;
              node.Text = c.Name + " : " + typ;
 
              foreach (Control item in c.Controls)
                 addStructure (node.Nodes, item);
           }
           else
           {
              node.Text = obj.ToString () + " : " + typ;
           }
 
           addAttributes (node.Nodes, obj);
 
           target.Add (node);
        }

Tabulka vlasností jednoho objektu

Funkce zavolaná po změně právě atkivního prvku ve stromu

        public void reflectionTree_AfterSelect (object sender, TreeViewEventArgs e)
        {
           object obj = e.Node.Tag;
           Type typ = obj.GetType ();
 
           propGrid.SelectedObject = obj;
           typeGrid.SelectedObject = obj.GetType ().GetTypeInfo();
 
           foreach (PropertyInfo prop in typ.GetProperties ())
           {
              string name = prop.Name;
              object value = null;
              if (prop.CanRead)
              {
                 value = prop.GetValue (obj, null); /* second parameter required from .Net 4.5 */
              }
              object [] line = new object [] {name, value};
              reflectionGrid.Rows.Add (line);
           }
        }

Atributy

Hlavnímu oknu jsem přidal několik atributů Description, které chci pomocí typových informací najít a zobrazit.

Reálným použití je například označení metod, které se objeví v kontextovém menu příklad na gitlab

    [Description ("Main Window")]
    public partial class TypeInfo : Form
    {
        [Description ("Compilation")]
        private CodeModule codeModule;
 
        [Description ("Reflection")]
        private ReflectionModule reflectionModule;
 
        [Description ("Open file")]
        private void open_Click (...) { }
 
        [Description ("Save file")]
        private void save_Click (...) { }
    }

Zobrazení atributů ve stromu

V zadaném objektu vyhledáme atribut (nebo několik atributů) typu DescriptionAttribute,
které jsme zadali pomocí [Description (”…”)] před deklarací třídy
a zobrazíme je jako modré položky ve stromu

        private void addAttributes (TreeNodeCollection target, object obj)
        {
            Type type = obj.GetType ();
            foreach (DescriptionAttribute attr in type.GetCustomAttributes<DescriptionAttribute> ())
            {
                TreeNode node = new TreeNode ();
                node.Tag = attr;
                node.Text = attr.Description;
                node.ForeColor = Color.CornflowerBlue;
                target.Add (node);
            }

Nebo můžeme zobrazit všechny atributy zadaného objektu

            foreach (Attribute attr in type.GetCustomAttributes ())
            {
                TreeNode node = new TreeNode ();
                node.Tag = attr;
                node.Text = attr.ToString ();
                node.ForeColor = Color.CornflowerBlue;
                target.Add (node);
            }

Zobrazíme atributy, které se váží k jednotlivým metodám.

            foreach (MethodInfo meth in type.GetRuntimeMethods ())
            {
                foreach (DescriptionAttribute attr in meth.GetCustomAttributes<DescriptionAttribute> ())
                {
                    TreeNode node = new TreeNode ();
                    node.Tag = attr;
                    node.Text = meth.Name + " : " + attr.Description;
                    node.ForeColor = Color.Orange;
                    target.Add (node);
                }
            }

Podobně zobrazíme atributy jednotlivých proměnných.

            foreach (FieldInfo field in type.GetRuntimeFields ())
            {
                var list = field.GetCustomAttributes<DescriptionAttribute> ();
                foreach (DescriptionAttribute attr in list)
                {
                    TreeNode node = new TreeNode ();
                    node.Tag = attr;
                    node.Text = field.Name + " : " + attr.Description;
                    node.ForeColor = Color.Lime;
                    target.Add (node);
                }
            }
        }

Obrázek našeho programu

Obrázek našeho programu se stromem, který zobrazuje strukturu hlavního okna.

V dolní části stromu jsou barevně zobrazeny Description attributy našeho okna.

Na záložce Properties naleznete vlastnosti zobrazené pomocí PropertyGrid.

Na záložce Reflection jsou vlastnosti zobrazené naším programem.

Třída ReflectionModule

    public class ReflectionModule
    {
        private TreeView reflectionTree;
        private PropertyGrid propGrid;
        private DataGridView reflectionGrid;
        private PropertyGrid typeGrid;
 
        public ReflectionModule (TreeView reflectionTree0, 
                                 PropertyGrid propGrid0,
                                 DataGridView reflectionGrid0,
                                 PropertyGrid typeGrid0)
        {
            reflectionTree = reflectionTree0;
            propGrid = propGrid0;
            reflectionGrid = reflectionGrid0;
            typeGrid = typeGrid0;
 
            reflectionTree.AfterSelect += reflectionTree_AfterSelect;
        }
 
        public void display (object obj)
        {
            addStructure (reflectionTree.Nodes, obj);
        }
 
        private void addStructure (TreeNodeCollection target, object obj)
        {
           TreeNode node = new TreeNode ();
           node.Tag = obj;
           string typ = obj.GetType().ToString();
 
           if (obj is Control)
           {
              Control c = obj as Control;
              node.Text = c.Name + " : " + typ;
 
              foreach (Control item in c.Controls)
                 addStructure (node.Nodes, item);
           }
           else
           {
              node.Text = obj.ToString () + " : " + typ;
           }
 
           addAttributes (node.Nodes, obj);
 
           target.Add (node);
        }
 
        private void addAttributes (TreeNodeCollection target, object obj)
        {
            Type type = obj.GetType ();
 
            /*
            foreach (Attribute attr in type.GetCustomAttributes ())
            {
                TreeNode node = new TreeNode ();
                node.Tag = attr;
                node.Text = attr.ToString ();
                node.ForeColor = Color.CornflowerBlue;
                target.Add (node);
            }
            */
 
            foreach (DescriptionAttribute attr in type.GetCustomAttributes<DescriptionAttribute> ())
            {
                TreeNode node = new TreeNode ();
                node.Tag = attr;
                node.Text = attr.Description;
                node.ForeColor = Color.CornflowerBlue;
                target.Add (node);
            }
 
            foreach (MethodInfo meth in type.GetRuntimeMethods ())
            {
                foreach (DescriptionAttribute attr in meth.GetCustomAttributes<DescriptionAttribute> ())
                {
                    TreeNode node = new TreeNode ();
                    node.Tag = attr;
                    node.Text = meth.Name + " : " + attr.Description;
                    node.ForeColor = Color.Orange;
                    target.Add (node);
                }
            }
 
            foreach (FieldInfo field in type.GetRuntimeFields ())
            {
                var list = field.GetCustomAttributes<DescriptionAttribute> ();
                foreach (DescriptionAttribute attr in list)
                {
                    TreeNode node = new TreeNode ();
                    node.Tag = attr;
                    node.Text = field.Name + " : " + attr.Description;
                    node.ForeColor = Color.Lime;
                    target.Add (node);
                }
            }
        }
 
        public void reflectionTree_AfterSelect (object sender, TreeViewEventArgs e)
        {
           object obj = e.Node.Tag;
           Type typ = obj.GetType ();
 
           propGrid.SelectedObject = obj;
           typeGrid.SelectedObject = obj.GetType ().GetTypeInfo();
 
           foreach (PropertyInfo prop in typ.GetProperties ())
           {
              string name = prop.Name;
              object value = null;
              if (prop.CanRead)
              {
                 value = prop.GetValue (obj, null); /* second parameter required from .Net 4.5 */
              }
              object [] line = new object [] {name, value};
              reflectionGrid.Rows.Add (line);
           }
        }
 
    } // end of class

Hlavní okno

    [Description ("Main Window")]
    public partial class TypeInfo : Form
    {
        [Description ("Compilation")]
        private CodeModule codeModule;
 
        [Description ("Reflection")]
        private ReflectionModule reflectionModule;
 
        public TypeInfo ()
        {
            InitializeComponent ();
            codeModule = new CodeModule (codeTree, propGrid);
            reflectionModule = new ReflectionModule (structureTree, propGrid, reflectionGrid, typeGrid);
            viewReflection_Click (null, null);
        }
 
        [Description ("Open file")]
        private void open_Click (object sender, EventArgs e)
        {
            if (openDialog.ShowDialog () == DialogResult.OK)
            {
                editor.Lines = File.ReadAllLines (openDialog.FileName);
            }
        }
 
        [Description ("Save file")]
        private void save_Click (object sender, EventArgs e)
        {
            if (saveDialog.ShowDialog () == DialogResult.OK)
            {
                File.WriteAllLines (saveDialog.FileName, editor.Lines);
            }
        } 
 
        private void quit_Click(object sender , EventArgs e)
        {
            Close ();
        }
 
        /* Reflection */
 
        void viewReflection_Click (object sender, EventArgs e)
        {
           leftTabs.SelectedTab = structureTab;
           rightTabs.SelectedTab = reflectionTab;
 
           structureTree.Nodes.Clear ();
           reflectionModule.display (this);
           structureTree.SelectedNode = structureTree.Nodes[0];
           structureTree.Nodes[0].Expand ();
        }
 
        /* Compilation */
 
        void compile_Click (object sender, EventArgs e)
        {
            leftTabs.SelectedTab = codeTab;
            centralTabs.SelectedTab = editorTab;
 
            info.Clear ();
            codeModule.compile (editor, info);
        }
 
    } // end of class

Kompilace zdrojového textu

Na http://stackoverflow.com jsem našel příklad jak zkompilovat zdrojový text, který máme uložený jen v proměnné typu string.

Jako zdrojový text použijeme text z editačního okénka a umístíme do jendoprvkového pole code.

Pomocí následnujícho kódu nám knihovny platformy .NET přeloží zdrojový text a výsledek uloží jen do paměti.

        public void compile (TextBox editor, TextBox info)
        {
            string[] code = { editor.Text };
 
            CompilerParameters CompilerParams = new CompilerParameters ();
 
            CompilerParams.GenerateInMemory = true;
            CompilerParams.TreatWarningsAsErrors = false;
            CompilerParams.GenerateExecutable = false;
            CompilerParams.CompilerOptions = "/optimize";
 
            string[] references = { "System.dll", "System.Data.dll" };
            CompilerParams.ReferencedAssemblies.AddRange (references);
 
            CSharpCodeProvider provider = new CSharpCodeProvider ();
            CompilerResults compile = provider.CompileAssemblyFromSource (CompilerParams, code);

Pokud během překladu dojde k chybám zobrazíme zprávy v dolním okénku info

            if (compile.Errors.HasErrors)
            {
                foreach (CompilerError ce in compile.Errors)
                {
                    info.AppendText (ce.ToString () + "\r\n");
                }
            }

Pokud se překlad povede zobrazí naše funkce displayAssembly informace o přeložené programu ve stromu.

V editoru je přednastaven následující zdrojový text

   namespace CodeFromFile
   {
      public class CodeFromFile
      {
         static public int Add(int a ,int b)
         {
            return a+b;
         }
      }
   }

Pokusíme zavolat funkci Add s parametry 5 a 10

   if (compile.Errors.HasErrors)
            { ... }
            else
            {
                displayAssembly (compile.CompiledAssembly);
 
                Module module = compile.CompiledAssembly.GetModules ()[0];
                Type mt = null;
                MethodInfo meth = null;
 
                if (module != null)
                    mt = module.GetType ("CodeFromFile.CodeFromFile");
 
                if (mt != null)
                    meth = mt.GetMethod ("Add");
 
                if (meth != null)
                {
                    int result = (int)meth.Invoke (null, new object[] { 5, 10 });
                    info.AppendText ("result = " + result);
                }
            }
 
        }

Funkce displayAssembly, displayModule, displayType, displayMember, … zobrazí ve stromu informace o přeloženém kódu

    public class CodeModule
    {
        private TreeView codeTree;
        private PropertyGrid propGrid;
 
        public CodeModule (TreeView codeTree0, PropertyGrid propGrid0)
        {
            codeTree = codeTree0;
            propGrid = propGrid0;
 
            codeTree.NodeMouseClick += codeTree_NodeMouseClick;
        }
 
        public void displayAssembly (Assembly a)
        {
            codeTree.Nodes.Clear ();
            foreach (Module m in a.GetModules ())
               displayModule (codeTree.Nodes, m);
        }
 
        private void displayModule (TreeNodeCollection target, Module m)
        {
            TreeNode node = new TreeNode();
            node.Text = "module " + m.Name;
            node.Tag = m;
            foreach (Type t in m.GetTypes ())
                displayType (node, t);
            target.Add (node);
        }
 
        private void displayType (TreeNode target, Type t)
        {
            TreeNode node = new TreeNode();
            node.Text = "type " + t.Name;
            node.Tag = t;
            foreach (MemberInfo m in t.GetMembers ())
                displayMember (node, m);
            target.Nodes.Add (node);
        }
 
        private void displayMember (TreeNode target, MemberInfo m)
        {
            TreeNode node = new TreeNode();
            node.Text = m.Name;
            node.Tag = m;
            if (m is MethodBase)
            {
                MethodBase b = m as MethodBase;
                foreach (ParameterInfo p in b.GetParameters ())
                    displayParameter (node, p);
            }
            if (m is MethodInfo)
            {
                displayResult (node, m as MethodInfo);
            }
            target.Nodes.Add (node);
        }
 
        private void displayParameter (TreeNode target, ParameterInfo p)
        {
            TreeNode node = new TreeNode();
            node.Text = p.Name + " : " + p.ParameterType.ToString ();
            node.Tag = p;
            target.Nodes.Add (node);
        }
 
        private void displayResult (TreeNode target, MethodInfo m)
        {
            TreeNode node = new TreeNode();
            node.Text = "result " + m.ReturnType.ToString ();
            target.Nodes.Add (node);
        }
 
        private void codeTree_NodeMouseClick (object sender, TreeNodeMouseClickEventArgs e)
        {
            propGrid.SelectedObject = e.Node.Tag;
        }
 
        /* code from stackoverflow.com */
 
        public void compile (TextBox editor, TextBox info)
        {
            string[] code = { editor.Text };
 
            CompilerParameters CompilerParams = new CompilerParameters ();
 
            CompilerParams.GenerateInMemory = true;
            CompilerParams.TreatWarningsAsErrors = false;
            CompilerParams.GenerateExecutable = false;
            CompilerParams.CompilerOptions = "/optimize";
 
            string[] references = { "System.dll", "System.Data.dll" };
            CompilerParams.ReferencedAssemblies.AddRange (references);
 
            CSharpCodeProvider provider = new CSharpCodeProvider ();
            CompilerResults compile = provider.CompileAssemblyFromSource (CompilerParams, code);
 
            if (compile.Errors.HasErrors)
            {
                string text = "Compile error: ";
                foreach (CompilerError ce in compile.Errors)
                {
                    info.AppendText (ce.ToString () + "\r\n");
                    text += "\r\n" + ce.ToString ();
                }
                // throw new Exception (text);
            }
            else
            {
                displayAssembly (compile.CompiledAssembly);
 
                Module module = compile.CompiledAssembly.GetModules ()[0];
                Type mt = null;
                MethodInfo meth = null;
 
                if (module != null)
                    mt = module.GetType ("CodeFromFile.CodeFromFile");
 
                if (mt != null)
                    meth = mt.GetMethod ("Add");
 
                if (meth != null)
                {
                    int result = (int)meth.Invoke (null, new object[] { 5, 10 });
                    info.AppendText ("result = " + result);
                }
            }
 
        }
 
    } // end of class

gitlab zip