Presentation is loading. Please wait.

Presentation is loading. Please wait.

Effective C# 50 Specific Way to Improve Your C# Item 42, 43.

Similar presentations


Presentation on theme: "Effective C# 50 Specific Way to Improve Your C# Item 42, 43."— Presentation transcript:

1 Effective C# 50 Specific Way to Improve Your C# Item 42, 43

2 Agenda Item 42: Utilize Attributes to Simplify Reflection Item 42: Utilize Attributes to Simplify Reflection Item 43: Don't Overuse Reflection Item 43: Don't Overuse Reflection

3 Item 42: Utilize Attributes to Simplify Reflection Item 42: Utilize Attributes to Simplify Reflection

4 Example: create a add-in framework Target: Add menu items and command handlers to a running software system Target: Add menu items and command handlers to a running software system – Drop an assembly into a directory – Find out about it – Add new menu items for the new command

5 Code (1) // Find all the assemblies in the Add-ins directory: string AddInsDir = string.Format("{0}/Addins", Application.StartupPath); string[] assemblies = Directory.GetFiles(AddInsDir, "*.dll"); foreach (string assemblyFile in assemblies) { Assembly asm = Assembly.LoadFrom(assemblyFile); // Find and install command handlers from the assembly. }

6 Code (2) Use attributes to figure out which exported types contain command handlers and which methods are the command handlers Attribute class marks the types that have command handlers Use attributes to figure out which exported types contain command handlers and which methods are the command handlers Attribute class marks the types that have command handlers // Define the Command Handler Custom Attribute: [AttributeUsage(AttributeTargets.Class)] public class CommandHandlerAttribute : Attribute { public CommandHandlerAttribute() { }

7 Code (3) // Find all the assemblies in the Add-ins directory: string AddInsDir = string.Format("{0}/Addins", Application.StartupPath); string[] assemblies = Directory.GetFiles(AddInsDir, "*.dll"); foreach (string assemblyFile in assemblies) { Assembly asm = Assembly.LoadFrom(assemblyFile); // Find and install command handlers from the assembly. foreach(System.Type t in asm.GetExportedTypes()) { if (t.GetCustomAttributes( typeof(CommandHandlerAttribute), false).Length > 0) { // Found the command handler attribute on this type. // This type implements a command handler. // configure and add it. } // Else, not a command handler. Skip it. }

8 Code (4) [AttributeUsage(AttributeTargets.Property) ] public class DynamicMenuAttribute : System.Attribute { private string _menuText; private string _parentText; public DynamicMenuAttribute(string CommandText, string ParentText) { _menuText = CommandText; _parentText = ParentText; } public string MenuText { get { return _menuText; } set { _menuText = value; } } public string ParentText { get { return _parentText; } set { _parentText = value; } }

9 Code (5-1) // Expanded from the first code sample: // Find the types in the assembly foreach(Type t in asm.GetExportedTypes()) { if (t.GetCustomAttributes(typeof(CommandHandlerAttribute), false).Length > 0) { // Found a command handler type: ConstructorInfo ci = t.GetConstructor(new Type[0]); if (ci == null) // No default ctor continue; object obj = ci.Invoke(null); PropertyInfo [] pi = t.GetProperties();

10 Code (5-2) // Find the properties that are command // handlers foreach(PropertyInfo p in pi) { string menuTxt = ""; string parentTxt = ""; object [] attrs = p.GetCustomAttributes( typeof (DynamicMenuAttribute), false); foreach (Attribute at in attrs) { DynamicMenuAttribute dym = at as DynamicMenuAttribute; if (dym != null) { // This is a command handler. menuTxt = dym.MenuText; parentTxt = dym.ParentText; MethodInfo mi = p.GetGetMethod(); EventHandler h = mi.Invoke(obj, null) as EventHandler; UpdateMenu(parentTxt, menuTxt, h); }

11 Code (5-3) private void UpdateMenu(string parentTxt, string txt,EventHandler cmdHandler) { MenuItem menuItemDynamic = new MenuItem(); menuItemDynamic.Index = 0; menuItemDynamic.Text = txt; menuItemDynamic.Click += cmdHandler; //Find the parent menu item. foreach (MenuItem parent in mainMenu.MenuItems) { if (parent.Text == parentTxt) { parent.MenuItems.Add(menuItemDynamic); return; } // Existing parent not found: MenuItem newDropDown = new MenuItem(); newDropDown.Text = parentTxt; mainMenu.MenuItems.Add(newDropDown); newDropDown.MenuItems.Add(menuItemDynamic); }

12 Code (6) [ CommandHandler ] public class CmdHandler { [DynamicMenu("Test Command", "Parent Menu")] public EventHandler CmdFunc { get { if (theCmdHandler == null) theCmdHandler = new System.EventHandler(this.DynamicCommandHandler); return theCmdHandler; } private void DynamicCommandHandler( object sender, EventArgs args) { // Contents elided. }

13 Summary Tag each type that provided a dynamic command handler with an attribute Tag each type that provided a dynamic command handler with an attribute – Easier to find the command handlers Apply AttributeTargets (another attribute) Apply AttributeTargets (another attribute) – limit where the dynamic command attribute can be applied – simplifies the difficult task of finding the sought types in a dynamically loaded assembly Without attributes, you need to define some naming convention to find the types and the elements Without attributes, you need to define some naming convention to find the types and the elements – Naming convention is a source of human error

14 Item 43: Don't Overuse Reflection Item 43: Don't Overuse Reflection

15 Reflection Benefits Benefits – Enables you to write software that is much more dynamic – Using reflection, an application can be upgraded with new capabilities by adding new components Defects Defects – C#'s type safety  the Invoke members use parameters and return values typed as System.Object

16 Usage 1: default constructor // Usage:Create a new object using reflection: Type t = typeof(MyType); MyType obj = NewInstance(t) as MyType; // Example factory function, based on Reflection: object NewInstance(Type t) { // Find the default constructor: ConstructorInfo ci = t.GetConstructor(new Type[ 0 ]); if (ci != null) // Invoke default constructor, and return // the new object. return ci.Invoke(null); // If it failed, return null. return null; } public MyType NewInstance() { return new MyType(); }

17 Usage 2: access function member // Example usage: Dispatcher.InvokeMethod(AnObject, "MyHelperFunc"); // Dispatcher Invoke Method: public void InvokeMethod (object o, string name) { // Find the member functions with that name. MemberInfo[] myMembers = o.GetType().GetMember(name); foreach(MethodInfo m in myMembers) { // Make sure the parameter list matches: if (m.GetParameters().Length == 0) // Invoke: m.Invoke(o, null); }

18 Usage 3: access function member // Example usage: object field = Dispatcher.RetrieveField (AnObject, "MyField"); // elsewhere in the dispatcher class: public object RetrieveField (object o, string name) { // Find the field. FieldInfo myField = o.GetType().GetField(name); if (myField != null) return myField.GetValue(o); else return null; }

19 Simpler alternatives for Reflection IMyInterface foo = obj as IMyInterface; if (foo != null) { foo.DoWork(); foo.Msg = "work is done."; }

20 public class MyType : IMyInterface { [FactoryFunction] public static IMyInterface CreateInstance() { return new MyType(); } #region IMyInterface public string Msg { get { return _msg; } set { _msg = value; } public void DoWork() { // details elided. } #endregion }

21 Summary Reflection is a powerful late-binding mechanism Reflection is a powerful late-binding mechanism – The.NET Framework uses it to implement data binding Creating code using class factories, delegates, and interfaces will produce more maintainable systems. Creating code using class factories, delegates, and interfaces will produce more maintainable systems.


Download ppt "Effective C# 50 Specific Way to Improve Your C# Item 42, 43."

Similar presentations


Ads by Google