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); }
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); } }
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 (...) { } }
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 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.
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
[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
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