C#反射(Reflection)詳解
C#反射技術(shù)主要基于System.Type類(lèi)和System.Reflection.Assemble類(lèi),通過(guò)Type類(lèi)可以訪問(wèn)關(guān)于任何數(shù)據(jù)類(lèi)型的信息,Assemble類(lèi)用于訪問(wèn)給定程序集的相關(guān)信息,或把這個(gè)程序集加載到程序中。
一.System.Type類(lèi)
Type類(lèi)是一個(gè)抽象類(lèi)。只要實(shí)例化了一個(gè)Type對(duì)象,實(shí)際上就實(shí)例化了Type的一個(gè)派生類(lèi)。盡管一般情況下派生類(lèi)只提供各種Type方法和屬性的不同重載,但是這些方法和屬性返回對(duì)應(yīng)數(shù)據(jù)類(lèi)型的正確數(shù)據(jù),Type有與每種數(shù)據(jù)類(lèi)型對(duì)應(yīng)的派生類(lèi)。它們一般不添加新的方法或?qū)傩?br />通常,獲取指向任何給定的Type引用有三種常用方式:
- *使用typeof運(yùn)算符,這個(gè)運(yùn)算符的參數(shù)是類(lèi)型的名稱(chēng),但不放在引號(hào)中:
Type t =typeof(double);
- *使用GetType()方法,所以類(lèi)都會(huì)從System.Object繼承這個(gè)方法:
double d =10; Type t = d.GetType();
在一個(gè)變量上調(diào)用GetType()方法,返回的Type對(duì)象只與該數(shù)據(jù)類(lèi)型相關(guān),不包含該類(lèi)型實(shí)例的任何信息。
- *調(diào)用Type類(lèi)的靜態(tài)方法GetType():
Type t =Type.GetType("System.Double");Type是很多反射功能的入口,它實(shí)現(xiàn)很多方法和屬性,可用的屬性都是只讀的:可以使用Type確定數(shù)據(jù)的類(lèi)型,但不能使用它修改該類(lèi)型。
1.Type屬性
由Type實(shí)現(xiàn)的屬性分為3類(lèi)。
- *包含與類(lèi)相關(guān)的各種名稱(chēng)的字符串:
- Name:數(shù)據(jù)類(lèi)型名
- FullName:數(shù)據(jù)類(lèi)型的完全限定名(包含名稱(chēng)空間)
- Namespace:在其中定義數(shù)據(jù)類(lèi)型的名稱(chēng)空間名
- *獲取Type對(duì)象的引用的屬性:
- BaseType:該對(duì)象的直接基本類(lèi)型
- UnderlyingSystemType:該Type在.NET運(yùn)行庫(kù)中映射到的類(lèi)型
- *布爾屬性
- IsAbstract,IsArray,IsClass,IsEnum等判斷Type是什么類(lèi)型的屬性。
2.方法
System.Type的大多數(shù)方法都用于獲取對(duì)應(yīng)數(shù)據(jù)類(lèi)型的成員信息:構(gòu)造函數(shù),屬性,方法和事件等。它有許多方法,但它們都有相同的模式。例如,獲取數(shù)據(jù)類(lèi)型的方法的信息:GetMethod()和GetMethods()。GetMethod()方法返回MethodInfo對(duì)象的一個(gè)引用,其中包含一個(gè)指定方法的細(xì)節(jié)信息;而GetMethods()返回這種引用的一個(gè)數(shù)組。

二.Assembly類(lèi)
Assembly類(lèi)允許訪問(wèn)給定程序集的元數(shù)據(jù),它也包含可以加載和執(zhí)行程序集(假定該程序集是可執(zhí)行的)的方法。與Type類(lèi)一樣,Assembly類(lèi)包含非常多的方法和屬性,這里只介紹與特性(//www.dbjr.com.cn/article/244250.htm)有關(guān)的成員,其它成員可以去MSDN(https://msdn.microsoft.com/zh-cn/library/system.reflection.assembly(v=vs.100).aspx)查看。



在使用Assembly實(shí)例做一些工作前,需要把相應(yīng)的程序集加載到正在運(yùn)行的進(jìn)程中??梢允褂渺o態(tài)方法Assembly.Load()或Assembly.LoadFrom()。Load()方法的參數(shù)程序集的名稱(chēng),運(yùn)行庫(kù)會(huì)在各個(gè)位置上搜索該程序集,這些位置包括本地目錄和全局程序集緩存。而LoadFrom()方法的參數(shù)是程序集的完整路徑名,它不會(huì)在其它位置搜索該程序集:
Assembly assembly1 = Assembly.Load(“WhatsNewAttributes"); Assembly assembly2 = Assembly.LoadFrom(“E:\WhatsNewAttributes\bin\Debug\WhatsNewAttributes");
這兩個(gè)方法都有許多其它重載版本。
1.獲取在程序集中定義的類(lèi)型的詳細(xì)信息
Assembly類(lèi)調(diào)用GetType()方法可以獲得相應(yīng)程序集中定義的所有類(lèi)型的詳細(xì)信息,它返回一個(gè)包含所有類(lèi)型的詳細(xì)信息的System.Type引用數(shù)組:
Type[] types = assembly1.GetType();
foreach(Type t in types)
{
}2.獲取自定義特性的詳細(xì)信息
如果需要確定程序集關(guān)聯(lián)了什么自定義特性,就需要調(diào)用Attribute類(lèi)的一個(gè)靜態(tài)方法GetCustomAttributes():
Assembly assembly1 = Assembly.Load(“WhatsNewAttributes"); Attribute[] attribs = Attribute.GetCustomAttributes(assembly1);
GetCustomAttributes方法用于獲取程序集的特性,他有兩個(gè)重載方法:如果在調(diào)用它時(shí),除了程序集的引用外,沒(méi)有其它參數(shù),該方法就會(huì)返回這個(gè)程序集定義的所以自定義特性;如果指定第二個(gè)參數(shù),第二個(gè)參數(shù)表示特性類(lèi)的一個(gè)Type對(duì)象,GetCustomAttributes方法返回指定特性類(lèi)型的特性數(shù)組。
所有的特性都作為一般的Attribute引用來(lái)獲取。如果需要調(diào)用為自定義特性定義的任何方法或?qū)傩裕托枰堰@些引用顯示轉(zhuǎn)換為自定義特性類(lèi)。
如果要獲得與方法,構(gòu)造函數(shù)和字段等的特性,就需要調(diào)用MethodInfo,ConstructorInfo,FieldInfo等類(lèi)的GetCustomAttributes()方法。
下面通過(guò)一個(gè)例子演示,自定義特性和反射
1.編寫(xiě)自定義特性
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.對(duì)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.通過(guò)反射獲取程序集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);
}
}
}到此這篇關(guān)于C#反射(Reflection)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Qt之調(diào)用C#的動(dòng)態(tài)庫(kù)的解決方法
這篇文章給大家介紹了Qt之調(diào)用C#的動(dòng)態(tài)庫(kù)的解決方法,環(huán)境使用的是VS2019+Qt5.12,感興趣的朋友一起看看吧2021-10-10
C#采用Winform實(shí)現(xiàn)類(lèi)似Android的Listener
這篇文章主要介紹了C#采用Winform實(shí)現(xiàn)類(lèi)似Android的Listener,很實(shí)用的技巧,需要的朋友可以參考下2014-08-08
C#對(duì)接阿里云IOT平臺(tái)進(jìn)行設(shè)備開(kāi)發(fā)
這篇文章介紹了C#對(duì)接阿里云IOT平臺(tái)進(jìn)行設(shè)備開(kāi)發(fā),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01
詳解C#實(shí)現(xiàn)在Excel單元格中應(yīng)用多種字體格式
在Excel中,可對(duì)單元格中的字符串設(shè)置多種不同樣式。本文,將以C#及VB.NET代碼為例,介紹如何在Excel同一個(gè)單元格中應(yīng)用多種字體樣式,感興趣的可以了解一下2022-05-05
C#中字符串與字節(jié)數(shù)組的轉(zhuǎn)換方式
這篇文章介紹了C#中字符串與字節(jié)數(shù)組的轉(zhuǎn)換方式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
C# 內(nèi)部類(lèi)與Lambda表達(dá)式用法詳解
Lambda表達(dá)式是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名,直接對(duì)應(yīng)于其中的lambda抽象,是一個(gè)匿名函數(shù),即沒(méi)有函數(shù)名的函數(shù);內(nèi)部類(lèi)是將一個(gè)類(lèi)定義在另一個(gè)給類(lèi)里面或者方法里面,這樣的類(lèi)就被稱(chēng)為內(nèi)部類(lèi)2021-10-10
C#生成帶二維碼的專(zhuān)屬微信公眾號(hào)推廣海報(bào)實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于利用C#如何生成帶二維碼的專(zhuān)屬微信公眾號(hào)推廣海報(bào)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們一起來(lái)看看吧2018-12-12

