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

  • první parametr target určuje místo ve stromu kam bude přidána nová položka
  • druhý parametr obj je odkaz na zobrazovaný objekt
  • vytvoříme nový uzel stromu node
  • do node.Tag si uložíme odlaz na objekt
  • jméno typu objektu získáme pomocí obj.GetType().ToString()
  • pokud je objekt odvozen ze třídy Control
    • přetypujeme objekt na Control, Control c = obj as Control
    • vnořené grafické prvky získáme pomocí c.Controls
    • rekurzivně zavoláme addStructure pro zobrazení vnořených prvků
  • funkce addAttributes popíšeme později, přidá do stromu informace o atributech
  • target.Add (node) přidá prvek do stromu
        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

  • vyzvedne odkaz na objekt object obj = e.Node.Tag
  • získá popis typu daného objektu Type typ = obj.GetType ()
  • na záložce Properties v tabulce propGrid typu PropertyGrid zobrazí vlastnosti objektu
  • na záložce Type Info zobrazí typové informace
  • na záložce Reflection se v tabulce reflectionGrid typu DataGridView pokusíme sami zobrazit vlastnosti objektu
  • typ.GetProperties () nám poskytne pole s prvky typu PropertyInfo obsahující popisy jednotlivých vlastností
  • ke každé vlastnosti, jejíř popis máme v proměnná prop, můžeme získat jméno prop.Name
  • pokud je vlastnost možné číst ( if (prop.CanRead) )
    • hodnotu uloženou jako obecný typ object přečteme pomocí prop.GetValue (obj, null)
      • prop je popis vlastnosti
      • obj je objekt ze kterého vlastnost čteme
  • vytvoříme pole objektů představující jednu řádku tabulky: object [] line = new object [] {name, value};
  • řádku přidáme do takulky: reflectionGrid.Rows.Add (line);
        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

  • obj - objekt ve kterém hledáme atributy
  • type - popis typu zadaného objektu
  • type.GetCustomAttributes <DescriptionAttribute> () pole s atributy Description
        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.

  • type.GetRuntimeMethods () poskytne pole popisů jednotlivých metod v daném typu
  • popis jedné metody meth je typu MethodInfo
  • seznam Description attributů získáme pomocí meth.GetCustomAttributes<DescriptionAttribute> ()
  • zobrazíme je jako oranžové prvky stromu
            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.

  • type.GetRuntimeFields () poskytne pole popisů jednotlivých proměnných
  • popis jedné proměnné field je typu FieldInfo
  • seznam Description attributů získáme pomocí field.GetCustomAttributes<DescriptionAttribute> ()
  • zobrazíme je jako zelené prvky stromu
            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

  • do proměnné module uložíme první modul z přeloženého assembly
  • do mt popis přeložené třídy CodeFromFile
  • do meth popis metody Add
  • funkci Add zavoláme pomocí meth.Invoke (null, new object[] { 5, 10 })
  • funkce Add je statická, tak instanci objektu zadáme jako null
  • pole parametrů bude new object[] { 5, 10 }
  • o výsledku přepokládáme, že bude celé číslo
  • výsledek zobrazíme v dolní části okna
   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

 
pw/reflexe.txt · Last modified: 2021/09/10 15:32 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki