Type reflection, late binding, and feature-based programming, reflecting late binding features
1. Reflection
Why pay attention to metadata? ------ Reflection Service
In .net, all types of lists contained in a specified .dllor .exe assembly can be obtained through reflection. The list includes methods, fields, attributes, and events defined for a given type. Reflection is obtained in reverse direction.
How to Use System. Reflection namespace programming to read. net metadata? The System. Type class is required.
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;using System.IO; // For FileNotFoundException definition.namespace ExternalAssemblyReflector{ class Program { #region Helper function static void DisplayTypesInAsm(Assembly asm) { Console.WriteLine("\n***** Types in Assembly *****"); Console.WriteLine("->{0}", asm.FullName); Type[] types = asm.GetTypes(); foreach (Type t in types) Console.WriteLine("Type: {0}", t); Console.WriteLine(""); } #endregion static void Main(string[] args) { Console.WriteLine("***** External Assembly Viewer *****"); string asmName = ""; Assembly asm = null; do { Console.WriteLine("\nEnter an assembly to evaluate"); Console.Write("or enter Q to quit: "); // Get name of assembly. asmName = Console.ReadLine(); // Does user want to quit? if (asmName.ToUpper() == "Q") { break; } // Try to load assembly. try { asm = Assembly.LoadFrom(asmName); DisplayTypesInAsm(asm); } catch { Console.WriteLine("Sorry, can't find assembly."); } } while (true); } }}
2. Late binding
Creating an instance of a given type and calling its members at runtime is important for program scalability because it does not need to be known during compilation.
The key to late binding is the System. Activator class.
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO;using System.Reflection;namespace LateBindingApp{ // This program will load an external library, // and create an object using late binding. public class Program { static void Main(string[] args) { Console.WriteLine("***** Fun with Late Binding *****"); // Try to load a local copy of CarLibrary. Assembly a = null; try { a = Assembly.Load("CarLibrary"); } catch (FileNotFoundException ex) { Console.WriteLine(ex.Message); return; } if (a != null) { // CreateUsingLateBinding(a); InvokeMethodWithArgsUsingLateBinding(a); } Console.ReadLine(); } #region Invoke method with no args static void CreateUsingLateBinding(Assembly asm) { try { // Get metadata for the Minivan type. Type miniVan = asm.GetType("CarLibrary.MiniVan"); // Create the Minivan on the fly. object obj = Activator.CreateInstance(miniVan); Console.WriteLine("Created a {0} using late binding!", obj); // Get info for TurboBoost. MethodInfo mi = miniVan.GetMethod("TurboBoost"); // Invoke method ('null' for no parameters). mi.Invoke(obj, null); } catch (Exception ex) { Console.WriteLine(ex.Message); } } #endregion #region Invoke method with args static void InvokeMethodWithArgsUsingLateBinding(Assembly asm) { try { // First, get a metadata description of the sports car. Type sport = asm.GetType("CarLibrary.SportsCar"); // Now, create the sports car. object obj = Activator.CreateInstance(sport); // Invoke TurnOnRadio() with arguments. MethodInfo mi = sport.GetMethod("TurnOnRadio"); mi.Invoke(obj, new object[] { true, 2 }); } catch (Exception ex) { Console.WriteLine(ex.Message); } } #endregion }}
3. Role of. net features.
.. Net platform allows programmers to use features to embed more metadata into a set of programs. features are used for types (such as classes, interfaces, and structures) and members (such as attributes and methods), assembly or module code annotation.
A feature is useful only when another software reflects its value.
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace ApplyingAttributes{ #region Simple classes for testing // This class can be saved to disk. [Serializable] public class Motorcycle { // However this field will not be persisted. [NonSerialized] float weightOfCurrentPassengers; // These fields are still serializable. bool hasRadioSystem; bool hasHeadSet; bool hasSissyBar; } [Serializable, Obsolete("Use another vehicle!")] public class HorseAndBuggy { // ... } #endregion class Program { static void Main(string[] args) { HorseAndBuggy mule = new HorseAndBuggy(); } }}
Reflection features
using System;using System.Collections.Generic;using System.Linq;using System.Text;using AttributedCarLibrary;namespace VehicleDescriptionAttributeReader{ class Program { static void Main(string[] args) { Console.WriteLine("***** Value of VehicleDescriptionAttribute *****\n"); ReflectOnAttributesWithEarlyBinding(); Console.ReadLine(); } private static void ReflectOnAttributesWithEarlyBinding() { // Get a Type representing the Winnebago. Type t = typeof(Winnebago); // Get all attributes on the Winnebago. object[] customAtts = t.GetCustomAttributes(false); // Print the description. foreach (VehicleDescriptionAttribute v in customAtts) Console.WriteLine("-> {0}\n", v.Description); } }}
Late Feature Binding
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;namespace VehicleDescriptionAttributeReaderLateBinding{ class Program { static void Main(string[] args) { Console.WriteLine("***** Value of VehicleDescriptionAttribute *****\n"); ReflectAttributesUsingLateBinding(); Console.ReadLine(); } #region Helper method private static void ReflectAttributesUsingLateBinding() { try { // Load the local copy of AttributedCarLibrary. Assembly asm = Assembly.Load("AttributedCarLibrary"); // Get type info of VehicleDescriptionAttribute. Type vehicleDesc = asm.GetType("AttributedCarLibrary.VehicleDescriptionAttribute"); // Get type info of the Description property. PropertyInfo propDesc = vehicleDesc.GetProperty("Description"); // Get all types in the assembly. Type[] types = asm.GetTypes(); // Iterate over each type and obtain any VehicleDescriptionAttributes. foreach (Type t in types) { object[] objs = t.GetCustomAttributes(vehicleDesc, false); // Iterate over each VehicleDescriptionAttribute and print // the description using late binding. foreach (object o in objs) { Console.WriteLine("-> {0}: {1}\n", t.Name, propDesc.GetValue(o, null)); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } #endregion }}
4. scalable applications
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Reflection;using CommonSnappableTypes;namespace MyExtendableApp{ public partial class MainForm : Form { public MainForm() { InitializeComponent(); } #region Menu handler private void snapInModuleToolStripMenuItem_Click(object sender, EventArgs e) { // Allow user to select an assembly to load. OpenFileDialog dlg = new OpenFileDialog(); if (dlg.ShowDialog() == DialogResult.OK) { if (dlg.FileName.Contains("CommonSnappableTypes")) MessageBox.Show("CommonSnappableTypes has no snap-ins!"); else if (!LoadExternalModule(dlg.FileName)) MessageBox.Show("Nothing implements IAppFunctionality!"); } } #endregion #region Load external assembly private bool LoadExternalModule(string path) { bool foundSnapIn = false; Assembly theSnapInAsm = null; try { // Dynamically load the selected assembly. theSnapInAsm = Assembly.LoadFrom(path); } catch (Exception ex) { MessageBox.Show(ex.Message); return foundSnapIn; } // Get all IAppFunctionality compatible classes in assembly. var theClassTypes = from t in theSnapInAsm.GetTypes() where t.IsClass && (t.GetInterface("IAppFunctionality") != null) select t; // Now, create the object and call DoIt() method. foreach (Type t in theClassTypes) { foundSnapIn = true; // Use late binding to create the type. IAppFunctionality itfApp = (IAppFunctionality)theSnapInAsm.CreateInstance(t.FullName, true); itfApp.DoIt(); lstLoadedSnapIns.Items.Add(t.FullName); // Show company info. DisplayCompanyData(t); } return foundSnapIn; } #endregion #region Show company info private void DisplayCompanyData(Type t) { // Get [CompanyInfo] data. var compInfo = from ci in t.GetCustomAttributes(false) where (ci.GetType() == typeof(CompanyInfoAttribute)) select ci; // Show data. foreach (CompanyInfoAttribute c in compInfo) { MessageBox.Show(c.CompanyUrl, string.Format("More info about {0} can be found at", c.CompanyName)); } } #endregion }}
For more detailed basic example reference: http://www.jb51.net/article/56029.htm