为何要关注元数据?------反射服务
在.net中,通过反射可以得到一个给定的.dll或.exe程序集所包含的所有类型的列表,列表包括给定类型定义的方法、字段、属性和事件,反射即反向获得。
如何使用System.Reflection命名空间编程读取.net元数据?需要借助System.Type类。
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); } } }
创建一个给定类型的实例,并且在运行时调用其成员,而不需要在编译时知道它存在的一种技术,对于程序的可扩展性来说很重要。
晚期绑定的关键是System.Activator类。
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 } }
.net平台允许程序员使用特性把更多的元数据嵌入到程序集中,特性就是用于类型(比如类、接口和结构)、成员(比如属性、方法)、程序集或模块的代码注解。
一个特性直到另一个软件反射它的值时才有用。
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(); } } }
反射特性
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); } } }
特性晚绑定
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 } }
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 } }
更详细的基础例子参照:http://www.jb51.net/article/56029.htm