您的位置:首页 > 其它

反射手册笔记 3.使用对象

2007-08-31 11:50 239 查看
本章是上一章的继续,再获取到对象类型后,接下来做的事情。

第一部分 动态调用成员——调用方法,检索或更改属性,以及字段

方法1:利用Info类调用类成员

1.用MethodInfo类调用方法:

object[] Invoke(object obj, Object[] parameters)

其中,第1个参数obj,是对象的实例(静态方法相应参数为null);第2个参数parameters是要传递到方法中的参数数组;返回值为object类型,因此,要对结果进行强制类型转换。示例如下:

public class MathClass

{

public int Multiply(int x, int y)

{

return x * y;

}

[STAThread]

static void Main()

{

MathClass objMath = new MathClass();

object[] paramArray = { 4, 5 };

MethodInfo method = objMath.GetType().GetMethod("Multiply");

int result = (int)method.Invoke(objMath, paramArray);

}

}

其中,objMath.GetType().GetMethod("Multiply")方法,默认搜索所有共有成员,可以使用其重载方法:

objMath.GetType().GetMethod("Multiply", BindingFlag.NonPublic),从而获取非公有成员。

2.用PropertyInfo类调用属性:

GetValue(Object obj, object[] index)

SetValue(Object obj, Object NewValue, object[] index)

其中,index为索引器(静态设为null),obj为对象的实例(静态设为null),返回值同样为object类型。示例如下:

public class Human

{

private string strName;

private string Name

{

get { return strName; }

set { strName = value; }

}

[STAThread]

static void Main()

{

Human newHuman = new Human();

//得到私有属性Name类型对象

PropertyInfo prop = newHuman.GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic);

//设置私有属性Name

string param = "Jax.Bao";

prop.SetValue(newHuman, param, null);

//获取私有属性Name

Console.WriteLine(prop.GetValue(newHuman, null).ToString());

}

}

3.用FieldInfo类调用字段:

GetValue(Object obj)

SetValue(Object obj, Object value)

FieldInfo类使用同PropertyInfo,只是没有Index罢了。示例略。

方法2:利用InvokeMember()方法调用类成员

3个重载,最常用的如下:

Object InvokeMember(

string name, //要调用的对象名:可以是属性名/方法名/字段名

BindingFlags invokeAttr, //搜索成员的条件,以及如何处理第一个参数:

//如BindingFlags.InvokeMethod表示第一个参数为方法名; //BindingFlags.GetProperty或SetProperty表示第一个参数为属性名;

//BindingFlags.SetField或GetField表示第一个参数为字段名;

Binder binder, //一般设为null,则会使用默认的DefaultBinder,对提供的参数进行类型转换,从原类型转为目标类型

Object target, //调用成员的类型的实例(静态成员为null)

Object[] args //对方法而言,是方法参数数组;对字段/属性而言,获取时是null,设置时是NewValue

);

1.调用方法:

MethodInfo类的Invoke()方法,不能直接处理重载方法,即无法判断使用哪个重载方法,而InvokeMember则可以自动找到匹配的重载方法。示例如下:

Type mathType = typeof(System.Math);

object[] paramArray = { 5, 8 };

int result = (int)mathType.InvokeMember("Max",

BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static,

null, null, paramArray);

当然,如果使用MethodInfo类的Invoke()方法处理重载方法,要辅助以SelectMethod()先找到对应的重载方法,然后才能调用。

2.操纵属性

得到属性用BindingFlags.GetProperty,同时参数数组为null;设置属性用BindingFlags.SetProperty,示例如下:

Type humanType = typeof(Human);

Human newHuman = new Human();

//设置私有属性Name

object[] paramArray = { "Jax.Bao" };

humanType.InvokeMember("Name",

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, newHuman, paramArray);

//得到私有属性Name类型对象

string result = humanType.InvokeMember("get_Name",

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, newHuman, null);

补注:

在MSIL中属性其实就是方法,所以对属性的操纵也可以使用如下方式(以get为例):

humanType.InvokeMember("get_Name",

BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, newHuman, null);

同理,可以使用MethodInfo.InvokeMethod()改写为:

Human objHuman = new Human();

Object[] paramArray = { "Jax.Bao" };

MethodInfo method = objHuman.GetType().GetMethod("get_Name");

string result = (string)method.Invoke(objHuman, paramArray);

3.操纵字段

基本上同于"操纵属性",不再多言。

两种方法的比较:

Type的InvokeMember()方法灵活且功能强大,应该优先使用;仅当需要处理元数据时,才使用info类。

第二部分 用反射模拟委托功能

之所以要模拟,是因为委托时类型安全的(编译期)——区别于反射(运行期),所以小型程序要尽量使用委托。

委托不区分静态方法/实例方法——区别于反射。

模拟代码如下:

public class Invoker

{

private Type myType;

private Object myObject;

private String myMethod;

public Invoker(Type targetType, String targetMethod)

{

myType = targetType;

myMethod = targetMethod;

}

public Invoker(Object targetObject, String targetMethod)

{

myObject = targetObject;

myType = targetObject.GetType();

myMethod = targetMethod;

}

public Object Invoke(Object[] args)

{

if (myType != null && myMethod != null)

{

BindingFlags myBindingFlags = BindingFlags.InvokeMethod | BindingFlags.Public;

if (myObject != null)

{

myBindingFlags = myBindingFlags | BindingFlags.Static;

}

else

{

myBindingFlags = myBindingFlags | BindingFlags.Instance;

}

return myType.InvokeMember(myMethod, myBindingFlags, null, myObject, args);

}

else

{

throw new Exception("Valid");

}

}

}

public class MyMath

{

public static int Pow(int x, int y)

{

return x ^ y;

}

public int Multiply(int x, int y)

{

return x * y;

}

static void Main()

{

try

{

Object result;

Object[] args = { 2, 3 };

MyMath objMath = new MyMath();

Invoker myDelegate = new Invoker(objMath, "Multiply");

result = myDelegate.Invoke(args);

Console.WriteLine("The product of {0} and {1} is: {2}", args[0], args[1], result);

Invoker objDelegate = new Invoker(typeof(MyMath), "Pow");

result = objDelegate.Invoke(args);

Console.WriteLine("The product of {0} and {1} is: {2}", args[0], args[1], result);

}

catch

{

throw;

}

}

}

在模拟中,委托可以使用委托链实现"反射"重载方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: