反射不經常使用,可是在開發一些基礎框架或公共類庫,使用反射會使系統更加靈活,有時甚至是惟一的選擇。反射是個龐大的話題,牽扯到的知識點也不少,包括程序集,自定義特性,泛型等等。
//獲取Type實例三種方法:
1.1 Type t = Type.GetType("System.IO.Stream");
1.2 Type t = typeof(System.IO.Stream);
1.3 Type t = "Hello".GetType();
//Type類型的基本信息
Type t = "Hello".GetType();
t.Name; //獲取類型名稱
t.FullName;//獲取類型全名
t.Namespace;//獲取名稱空間
t.BaseType;//獲取對基類的Type類型的引用
t.UnderlyingSystemType;
t.Attributes;//獲取TypeAttributes位標記
t.IsValueType;
t.IsByRef;
t.IsEnum;
t.IsClass;
t.IsInterface;
t.IsSealed;
t.IsPrimitive;//是否基類型
t.IsAbstract;
t.IsPublic;
t.IsVisible;
……
//Type類型的成員信息
//包含哪些字段,字段名稱,類型,可訪問性--FieldInfo
//包含哪些屬性,屬性名稱,類型,可訪問性--PropertyInfo
//包含哪些方法,方法名稱,返回值,參數個數,參數類型,參數名稱--MethodInfo
//事件 EventInfo 參數ParameterInfo
t.GetFields();
t.GetProperties();
t.GetMethods();
t.GetProperties();
t.GetConstructor();
t.GetMembers(BindingFlags.ExactBinding | BindingFlags.DeclaredOnly);
……
//位標記
//.NET中的枚舉咱們通常有兩種用法:
//一是表示惟一的元素序列,例如一週裏的各天;
//還有就是用來表示多種複合的狀態,這個時候通常須要爲枚舉加上[Flags]特性標記爲位域
//例如:
[Flags]
public enum BindingFlags
{
Default = 0,
IgnoreCase = 1,
DeclaredOnly = 2,
Instance = 4,
Static = 8,
Public = 16,
NonPublic = 32,
FlattenHierarchy = 64,
InvokeMethod = 256,
CreateInstance = 512,
GetField = 1024,
SetField = 2048
}
1.1 Assembly am = Assembly.LoadFrom("Demo.dll");
1.2 Assembly am = Assembly.Load("Demo");
1.3 Assembly am = typeof(int).Assembly;
1.4 獲取當前程序集
Assembly am = Assembly.GetExecutingAssembly();
am.FullName;//程序集名稱
am.Location; //路徑
am.GetTypes();//所有類型
am.GetType();//某個類型
am.GetModules();
am.GetModule();
am.GetCustomAttributes();
Module[] modules = am.GetModules();
foreach (Module module in modules)
{
Console.WriteLine("模塊:" + module);
//Demo.dll
foreach (Type t in module.GetTypes())
Console.WriteLine("類型:" + module);
//Demo.BaseClass Demo.Delegate Demo.Struct Demo.Interface Demo.DemoClass
}
1.獲取基本類型
2.獲取成員信息和MemberInfo類型
3.字段信息和FieldInfo
4.屬性信息和PropertyInfo
5.方法信息和MethodInfo
6.……
//反射枚舉
public static class EnumManager<TEnum>
{
private static DataTable GetDataTable()
{
Type t = typeof (TEnum);
FieldInfo[] fieldInfos = t.GetFields();
DataTable table=new DataTable();
table.Columns.Add("Name", Type.GetType("System.String"));
table.Columns.Add("Value", Type.GetType("System.Int32"));
foreach (FieldInfo field in fieldInfos)
{
if (field.IsSpecialName)
{
DataRow row = table.NewRow();
row[0] = field.Name;
row[1] = Convert.ToInt32(field.GetRawConstantValue());
table.Rows.Add(row);
}
}
return table;
}
}
特性:特性是一種特殊的類型,能夠加載到程序集的各類類型上,包括模塊,類,接口,結構,構造函數,方法,方法參數等。特性是爲程序集添加元數據的一種機制,經過他能夠爲編譯器提供指示或對數據的說明。
1.自定義特性:
//AllowMultiple=true表示能夠重複添加到一個類型上
[AttributeUsage(AttributeTargets.Class,AllowMultiple=true,Inherited = false)]
public class RecordAttribute:Attribute
{
private string recordType;
private string author;
private DateTime date;
private string memo;
public RecordAttribute(string recordType, string author, string date)
{
this.recordType = recordType;
this.author = author;
this.date = Convert.ToDateTime(date);
}
public string RecordType { get { return recordType; } }
public string Author { get { return author; } }
public DateTime Date { get { return date; } }
public string Memo { get { return memo; }set { memo = value; }}
}
2.使用特性
//特性使用:僅寫成一行,無論是構造函數參數仍是屬性,所有寫到構造函數的圓括號中
//對應屬性,採用「屬性=值」的格式
[Record("更新","jackyfei","2016-08-24")]
[Record("建立","張飛洪","2016-08-14",Memo = "這個類是演示用的")]
public class DemoClass
{
}
3.反射特性
//使用特性對類型進行標記,目的是爲了在程序中的某處使用它。
Type t = typeof(DemoClass);
object[] records = t.GetCustomAttributes(typeof (RecordAttribute), false);
foreach (RecordAttribute record in records)
{
Console.WriteLine("{0}", record);
Console.WriteLine(" 類型:{0}", record.RecordType);
Console.WriteLine(" 做者:{0}", record.Author);
Console.WriteLine(" 日期:{0}", record.Date.ToShortDateString());
Console.WriteLine(" 備註:{0}", record.Memo);
}
//獲取到特性對象後,就能夠任意處理了,好比說導出程序註釋
前面的知識內容,主要是利用反射查看類型,查看特性,程序集,都是屬於查看元數據的信息的內容。接下來將學習如何用反射動態建立一個對象。之因此叫動態,是由於能夠字符串能夠由各類途徑得到
[Record("更新", "jackyfei", "2016-08-24")]
[Record("建立", "張飛洪", "2016-08-14", Memo = "這個類是演示用的")]
public class Calculator
{
private int x;
private int y;
public Calculator()
{
x = 0;
y = 0;
Console.WriteLine("x:{0},y:{1}", x, y);
}
public Calculator(int x,int y)
{
this.x = x;
this.y = y;
Console.WriteLine("x:{0},y:{1}",x,y);
}
public string GetStr()
{
return "hello,jackyfei";
}
public int Add()
{
int total = 0;
total = x + y;
return total;
}
public static int Add(int x,int y)
{
int total = x + y;
return total;
}
1. 使用無參構造函數創造對象
//建立對象一
Assembly am = Assembly.GetExecutingAssembly();
DemoClass demoClass= am.CreateInstance("NameSpace.DemoClass", true) as DemoClass;
Console.WriteLine(demoClass.GetStr());
//建立對象二
//第一個參數是程序集的名稱,null表示當前程序集;
ObjectHandle handler = Activator.CreateInstance(null, "NameSpace.DemoClass");
handler.Unwrap();
2. 使用有參構造函數創造對象
Assembly am2 = Assembly.GetExecutingAssembly();
Object[] parameters=new object[2];
parameters[0] = 3;
parameters[1] = 5;
//BindingFlags用於限定類型成員的搜索,Default意思是不使用這個策略
am2.CreateInstance("NameSpace.DemoClass", true, BindingFlags.Default,
null, parameters, null, null);
1.1 InvokeMember()調用方式
Type t = typeof (Calculator);
Calculator c=new Calculator(3,5);
int rst =(int)t.InvokeMember("Add", BindingFlags.InvokeMethod, null, c, null);
Console.WriteLine("x+y={0}", rst);
object[] p = {6, 7};
int rst2 = (int)t.InvokeMember("Add", BindingFlags.InvokeMethod, null, t, p);
Console.WriteLine("x+y={0}", rst2);
//調用靜態方法,他不是基於某個具體的類型實例,而是基於類型自己,
//因此傳遞的參數是typeof(Calculator)
1.2 GetMethod()調用方式
Type t = typeof (Calculator);
Calculator c=new Calculator(3,5);
//BindingFlags.Instance 調用實例方法
MethodInfo mi = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);
int rst = (int)mi.Invoke(c, null);
Console.WriteLine("x+y={0}", rst);
//BindingFlags.Static 調用靜態方法
object[] p = { 6, 9 };
MethodInfo mi2 = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public);
int rst2 = (int)mi2.Invoke(null, p);
Console.WriteLine("x+y={0}", rst2);