.NET反射提供了在運行時獲取對象類型元數據的途徑,使程序可以動態地調用對象的屬性、方法。動態性帶來的代價是反射調用不像基於靜態類型的直接調用那樣簡潔,且缺乏類型檢查機制,失去了IDE智能提示,容易出錯;於是,不少朋友嘗試對.NET反射進行封裝。這個話題是仁者見仁,智者見智,這裡我也談談自己對.Net反射封裝的思路,請先看下面的示例代碼:
static void Main(string[] args)
{
Person liu = new Person("liu", 26);
Reflector reflector = new Reflector(liu);
//獲取屬性
string name = reflector.Property<string>("Name");
int age = reflector.Property<int>("Age");
Console.WriteLine(name + " " + age);
//修改屬性
age = reflector.SetProperty<int>("Age", 27);
Console.WriteLine(name + " " + age);
//獲取過程
Proc<string> sayHello = reflector.Proc<string>("SayHello");
sayHello("Ling");
//獲取函數
Func<int> getAge = reflector.Func<int>("GetAge");
age = getAge();
Console.WriteLine(age);
Console.ReadLine();
}
public class Person
{
private string name;
private int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
}
public int Age
{
get { return age; }
set { age = value; }
}
public void SayHello(string who)
{
Console.WriteLine("Say Hello to " + who);
}
public int GetAge()
{
return age;
}
}
相信您已經從代碼看出了封裝的思路:利用泛型和泛型委托為動態的反射添加靜態的類型約束。下面我們就來簡單看一下Reflector實現的關鍵部分:
public delegate void Proc();
public delegate void Proc<T1>(T1 arg1);
public delegate void Proc<T1, T2>(T1 arg1, T2 args);
public delegate void Proc<T1, T2, T3>(T1 arg1, T2 args, T3 arg3);
public delegate void Proc<T1, T2, T3, T4>(T1 arg1, T2 args, T3 arg3, T4 arg4);
public delegate void Proc<T1, T2, T3, T4, T5>(T1 arg1, T2 args, T3 arg3, T4 arg4, T5 arg5);
public delegate R Func<R>();
public delegate R Func<T1, R>(T1 arg1);
public delegate R Func<T1, T2, R>(T1 arg1, T2 args);
public delegate R Func<T1, T2, T3, R>(T1 arg1, T2 args, T3 arg3);
public delegate R Func<T1, T2, T3, T4, R>(T1 arg1, T2 args, T3 arg3, T4 arg4);
public delegate R Func<T1, T2, T3, T4, T5, R>(T1 arg1, T2 args, T3 arg3, T4 arg4, T5 arg5);
public class Reflector
{
private object target;
public object Target
{
get { return target; }
}
public T Property<T>(string name)
{
PropertyInfo pi = target.GetType().GetProperty(name, typeof(T));
if (null != pi && pi.CanRead)
{
object value = pi.GetValue(target, null);
if (null != value)
{
return (T)value;
}
}
return default(T);
}
public T SetProp
erty<T>(string name, T value)
{
PropertyInfo pi = target.GetType().GetProperty(name, typeof(T));
if (null != pi && pi.CanWrite)
{
pi.SetValue(target, value, null);
}
return value;
}
public Proc Proc(string name)
{
MethodInfo mi = target.GetType().GetMethod(name, Type.EmptyTypes);
if (null != mi)
{
return Delegate.CreateDelegate(typeof(Proc), target, mi.Name, false) as Proc;
}
return null;
}
public Proc<T> Proc<T>(string name)
{
MethodInfo mi = target.GetType().GetMethod(name, new Type[] { typeof(T) });
if (null != mi)
{
return Delegate.CreateDelegate(typeof(Proc<T>), target, mi.Name, false) as Proc<T>;
}
return null;
}
public Proc<T1, T2> Proc<T1, T2>(string name)
{
MethodInfo mi = target.GetType().GetMethod(name, new Type[] { typeof(T1), typeof(T2) });
if (null != mi)
{
return Delegate.CreateDelegate(typeof(Proc<T1, T2>), target, mi.Name, false) as Proc<T1, T2>;
}
return null;
}
public Proc<T1, T2, T3> Proc<T1, T2, T3>(string name)
{
//...
}
public Proc<T1, T2, T3, T4> Proc<T1, T2, T3, T4>(string name)
{
//...
}
public Proc<T1, T2, T3, T4, T5> Proc<T1, T2, T3, T4, T5>(string name)
{
//...
}
public Func<R> Func<R>(string name)
{
MethodInfo mi = target.GetType().GetMethod(name, Type.EmptyTypes);
if (null != mi)
{
return Delegate.CreateDelegate(typeof(Func<R>), target, mi.Name, false) as Func<R>;
}
return null;
}
public Func<T1, R> Func<T1, R>(string name)
{
MethodInfo mi = target.GetType().GetMethod(name, new Type[] { typeof(T1) });
if (null != mi)
{
return Delegate.CreateDelegate(typeof(Func<T1, R>), target, mi.Name, false) as Func<T1, R>;
}
return null;
}
public Func<T1, T2, R> Func<T1, T2, R>(string name)
{
//...
}
}
封裝的實現並不復雜,只是利用了泛型和泛型委托為調用者提供了強類型的屬性和方法;除屬性和方法的名稱是動態的以為,其余的都可以加上類型約束。歡迎就此話題多多交流!