C#反射(Reflection)詳解
C#反射技術主要基于System.Type類和System.Reflection.Assemble類,通過Type類可以訪問關于任何數(shù)據類型的信息,Assemble類用于訪問給定程序集的相關信息,或把這個程序集加載到程序中。
一.System.Type類
Type類是一個抽象類。只要實例化了一個Type對象,實際上就實例化了Type的一個派生類。盡管一般情況下派生類只提供各種Type方法和屬性的不同重載,但是這些方法和屬性返回對應數(shù)據類型的正確數(shù)據,Type有與每種數(shù)據類型對應的派生類。它們一般不添加新的方法或屬性
通常,獲取指向任何給定的Type引用有三種常用方式:
- *使用typeof運算符,這個運算符的參數(shù)是類型的名稱,但不放在引號中:
Type t =typeof(double);
- *使用GetType()方法,所以類都會從System.Object繼承這個方法:
double d =10; Type t = d.GetType();
在一個變量上調用GetType()方法,返回的Type對象只與該數(shù)據類型相關,不包含該類型實例的任何信息。
- *調用Type類的靜態(tài)方法GetType():
Type t =Type.GetType("System.Double");
Type是很多反射功能的入口,它實現(xiàn)很多方法和屬性,可用的屬性都是只讀的:可以使用Type確定數(shù)據的類型,但不能使用它修改該類型。
1.Type屬性
由Type實現(xiàn)的屬性分為3類。
- *包含與類相關的各種名稱的字符串:
- Name:數(shù)據類型名
- FullName:數(shù)據類型的完全限定名(包含名稱空間)
- Namespace:在其中定義數(shù)據類型的名稱空間名
- *獲取Type對象的引用的屬性:
- BaseType:該對象的直接基本類型
- UnderlyingSystemType:該Type在.NET運行庫中映射到的類型
- *布爾屬性
- IsAbstract,IsArray,IsClass,IsEnum等判斷Type是什么類型的屬性。
2.方法
System.Type的大多數(shù)方法都用于獲取對應數(shù)據類型的成員信息:構造函數(shù),屬性,方法和事件等。它有許多方法,但它們都有相同的模式。例如,獲取數(shù)據類型的方法的信息:GetMethod()和GetMethods()。GetMethod()方法返回MethodInfo對象的一個引用,其中包含一個指定方法的細節(jié)信息;而GetMethods()返回這種引用的一個數(shù)組。
二.Assembly類
Assembly類允許訪問給定程序集的元數(shù)據,它也包含可以加載和執(zhí)行程序集(假定該程序集是可執(zhí)行的)的方法。與Type類一樣,Assembly類包含非常多的方法和屬性,這里只介紹與特性(//chabaoo.cn/article/244250.htm)有關的成員,其它成員可以去MSDN(https://msdn.microsoft.com/zh-cn/library/system.reflection.assembly(v=vs.100).aspx)查看。
在使用Assembly實例做一些工作前,需要把相應的程序集加載到正在運行的進程中??梢允褂渺o態(tài)方法Assembly.Load()或Assembly.LoadFrom()。Load()方法的參數(shù)程序集的名稱,運行庫會在各個位置上搜索該程序集,這些位置包括本地目錄和全局程序集緩存。而LoadFrom()方法的參數(shù)是程序集的完整路徑名,它不會在其它位置搜索該程序集:
Assembly assembly1 = Assembly.Load(“WhatsNewAttributes"); Assembly assembly2 = Assembly.LoadFrom(“E:\WhatsNewAttributes\bin\Debug\WhatsNewAttributes");
這兩個方法都有許多其它重載版本。
1.獲取在程序集中定義的類型的詳細信息
Assembly類調用GetType()方法可以獲得相應程序集中定義的所有類型的詳細信息,它返回一個包含所有類型的詳細信息的System.Type引用數(shù)組:
Type[] types = assembly1.GetType(); foreach(Type t in types) { }
2.獲取自定義特性的詳細信息
如果需要確定程序集關聯(lián)了什么自定義特性,就需要調用Attribute類的一個靜態(tài)方法GetCustomAttributes():
Assembly assembly1 = Assembly.Load(“WhatsNewAttributes"); Attribute[] attribs = Attribute.GetCustomAttributes(assembly1);
GetCustomAttributes方法用于獲取程序集的特性,他有兩個重載方法:如果在調用它時,除了程序集的引用外,沒有其它參數(shù),該方法就會返回這個程序集定義的所以自定義特性;如果指定第二個參數(shù),第二個參數(shù)表示特性類的一個Type對象,GetCustomAttributes方法返回指定特性類型的特性數(shù)組。
所有的特性都作為一般的Attribute引用來獲取。如果需要調用為自定義特性定義的任何方法或屬性,就需要把這些引用顯示轉換為自定義特性類。
如果要獲得與方法,構造函數(shù)和字段等的特性,就需要調用MethodInfo,ConstructorInfo,FieldInfo等類的GetCustomAttributes()方法。
下面通過一個例子演示,自定義特性和反射
1.編寫自定義特性
namespace WhatsNewAttributes { [AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public class LastModifiedAttribute : Attribute { private readonly DateTime _dateModified; private readonly string _changes; public LastModifiedAttribute(string dateModified, string changes) { _dateModified = DateTime.Parse(dateModified); _changes = changes; } public DateTime DateModified { get { return _dateModified; } } public string Changes { get { return _changes; } } public string Issues { get; set; } } [AttributeUsage(AttributeTargets.Assembly)] public class SupportsWhatsNewAttribute : Attribute { } }
2.對VectorClass和其成員使用自定義特性
[assembly: SupportsWhatsNew] namespace VectorClass { [LastModified("14 Feb 2010", "IEnumerable interface implemented " + "So Vector can now be treated as a collection")] [LastModified("10 Feb 2010", "IFormattable interface implemented " + "So Vector now responds to format specifiers N and VE")] class Vector : IFormattable, IEnumerable { public double x, y, z; public Vector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } [LastModified("10 Feb 2010", "Method added in order to provide formatting support")] public string ToString(string format, IFormatProvider formatProvider) { if (format == null) return ToString(); string formatUpper = format.ToUpper(); switch (formatUpper) { case "N": return "|| " + Norm().ToString() + " ||"; case "VE": return String.Format("( {0:E}, {1:E}, {2:E} )", x, y, z); case "IJK": StringBuilder sb = new StringBuilder(x.ToString(), 30); sb.Append(" i + "); sb.Append(y.ToString()); sb.Append(" j + "); sb.Append(z.ToString()); sb.Append(" k"); return sb.ToString(); default: return ToString(); } } public Vector(Vector rhs) { x = rhs.x; y = rhs.y; z = rhs.z; } [LastModified("14 Feb 2010", "Method added in order to provide collection support")] public IEnumerator GetEnumerator() { return new VectorEnumerator(this); } public override string ToString() { return "( " + x + " , " + y + " , " + z + " )"; } public double this[uint i] { get { switch (i) { case 0: return x; case 1: return y; case 2: return z; default: throw new IndexOutOfRangeException( "Attempt to retrieve Vector element" + i); } } set { switch (i) { case 0: x = value; break; case 1: y = value; break; case 2: z = value; break; default: throw new IndexOutOfRangeException( "Attempt to set Vector element" + i); } } } public static bool operator ==(Vector lhs, Vector rhs) { if (System.Math.Abs(lhs.x - rhs.x) < double.Epsilon && System.Math.Abs(lhs.y - rhs.y) < double.Epsilon && System.Math.Abs(lhs.z - rhs.z) < double.Epsilon) return true; else return false; } public static bool operator !=(Vector lhs, Vector rhs) { return !(lhs == rhs); } public static Vector operator +(Vector lhs, Vector rhs) { Vector result = new Vector(lhs); result.x += rhs.x; result.y += rhs.y; result.z += rhs.z; return result; } public static Vector operator *(double lhs, Vector rhs) { return new Vector(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); } public static Vector operator *(Vector lhs, double rhs) { return rhs * lhs; } public static double operator *(Vector lhs, Vector rhs) { return lhs.x * rhs.x + lhs.y + rhs.y + lhs.z * rhs.z; } public double Norm() { return x * x + y * y + z * z; } #region enumerator class [LastModified("14 Feb 2010", "Class created as part of collection support for Vector")] private class VectorEnumerator : IEnumerator { readonly Vector _theVector; // Vector object that this enumerato refers to int _location; // which element of _theVector the enumerator is currently referring to public VectorEnumerator(Vector theVector) { _theVector = theVector; _location = -1; } public bool MoveNext() { ++_location; return (_location > 2) ? false : true; } public object Current { get { if (_location < 0 || _location > 2) throw new InvalidOperationException( "The enumerator is either before the first element or " + "after the last element of the Vector"); return _theVector[(uint)_location]; } } public void Reset() { _location = -1; } } #endregion } }
3.通過反射獲取程序集VectorClass和其成員的自定義特性
namespace LookUpWhatsNew { internal class WhatsNewChecker { private static readonly StringBuilder outputText = new StringBuilder(1000); private static DateTime backDateTo = new DateTime(2010, 2, 1); private static void Main() { Assembly theAssembly = Assembly.Load("VectorClass"); Attribute supportsAttribute = Attribute.GetCustomAttribute( theAssembly, typeof (SupportsWhatsNewAttribute)); string name = theAssembly.FullName; AddToMessage("Assembly: " + name); if (supportsAttribute == null) { AddToMessage( "This assembly does not support WhatsNew attributes"); return; } else { AddToMessage("Defined Types:"); } Type[] types = theAssembly.GetTypes(); foreach (Type definedType in types) DisplayTypeInfo(definedType); MessageBox.Show(outputText.ToString(), "What\'s New since " + backDateTo.ToLongDateString()); Console.ReadLine(); } private static void DisplayTypeInfo(Type type) { // make sure we only pick out classes if (!(type.IsClass)) return; AddToMessage("\nclass " + type.Name); Attribute[] attribs = Attribute.GetCustomAttributes(type); if (attribs.Length == 0) AddToMessage("No changes to this class"); else foreach (Attribute attrib in attribs) WriteAttributeInfo(attrib); MethodInfo[] methods = type.GetMethods(); AddToMessage("CHANGES TO METHODS OF THIS CLASS:"); foreach (MethodInfo nextMethod in methods) { object[] attribs2 = nextMethod.GetCustomAttributes( typeof (LastModifiedAttribute), false); if (attribs2 != null) { AddToMessage( nextMethod.ReturnType + " " + nextMethod.Name + "()"); foreach (Attribute nextAttrib in attribs2) WriteAttributeInfo(nextAttrib); } } } private static void WriteAttributeInfo(Attribute attrib) { LastModifiedAttribute lastModifiedAttrib = attrib as LastModifiedAttribute; if (lastModifiedAttrib == null) return; // check that date is in range DateTime modifiedDate = lastModifiedAttrib.DateModified; if (modifiedDate < backDateTo) return; AddToMessage(" MODIFIED: " + modifiedDate.ToLongDateString() + ":"); AddToMessage(" " + lastModifiedAttrib.Changes); if (lastModifiedAttrib.Issues != null) AddToMessage(" Outstanding issues:" + lastModifiedAttrib.Issues); } private static void AddToMessage(string message) { outputText.Append("\n" + message); } } }
到此這篇關于C#反射(Reflection)的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
C#采用Winform實現(xiàn)類似Android的Listener
這篇文章主要介紹了C#采用Winform實現(xiàn)類似Android的Listener,很實用的技巧,需要的朋友可以參考下2014-08-08詳解C#實現(xiàn)在Excel單元格中應用多種字體格式
在Excel中,可對單元格中的字符串設置多種不同樣式。本文,將以C#及VB.NET代碼為例,介紹如何在Excel同一個單元格中應用多種字體樣式,感興趣的可以了解一下2022-05-05