===== 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 [[https://gitlab.fjfi.cvut.cz/culikzde/pw-sharpdevelop/-/tree/master/Attr|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 ()** pole s atributy **Description** private void addAttributes (TreeNodeCollection target, object obj) { Type type = obj.GetType (); foreach (DescriptionAttribute attr in type.GetCustomAttributes ()) { 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 ()** * zobrazíme je jako //oranžové// prvky stromu foreach (MethodInfo meth in type.GetRuntimeMethods ()) { foreach (DescriptionAttribute attr in meth.GetCustomAttributes ()) { 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 ()** * zobrazíme je jako //zelené// prvky stromu foreach (FieldInfo field in type.GetRuntimeFields ()) { var list = field.GetCustomAttributes (); 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. {{typeinfo.png}} ===== 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 ()) { 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 ()) { 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 (); 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 {{typeinfo_compile.png}} [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/tree/master/TypeInfo|gitlab]] [[http://kmlinux.fjfi.cvut.cz/~culikzde/pw/TypeInfo2020.zip|zip]]