您的位置:首页 > 其它

如何通过反射调用方法?

2009-10-09 23:08 447 查看
在许多代码方案中,在执行任务以前您知道要实现的任务。因此,您可以指定需要调用的方法以及需要传递给它们的参数。但是,还有一些情况下您可能希望根据特定方案或用户操作动态调用方法。该功能可通过 Reflection 命名空间使用,方法是使用 Type 对象上的 InvokeMember 方法。

您还可以进行其他操作,如获取或设置指定属性的值。这些操作可通过 BindingFlags 枚举使用。InvokeMethod 的第二个参数是您指定的 BindingFlags 操作的组合。例如,如果想调用某个类上的静态方法,可以在 BindingFlagsInvokeMethod BindingFlag 中包括该静态元素。下面的示例展示如何调用名为 SayHello 的假想方法,其中 SayHello 是静态方法。

// calling a static method, receiving no arguments

// don't forget that we are using object in the reflection namespace...
using System;
using System.Reflection;

public class Invoke {

public static void Main (String [] cmdargs) {

// Declare a type object, used to call our InvokeMember method...
Type t = typeof (TestClass);

// BindingFlags has three bitor'ed elements. Default indicates
// that default binding rules should be applied.
t.InvokeMember ("SayHello",
BindingFlags.Default | BindingFlags.InvokeMethod
| BindingFlags.Static, null,
null, new object [] {});
}
}

'  calling a static method, receiving no arguments

'  don't forget that we are using object in the reflection namespace...
Imports System
Imports System.Reflection

Public Class Invoke

Public Shared Sub Main ()

'  Declare a type object, used to call our InvokeMember method...
Dim t As Type = GetType (TestClass)

'  BindingFlags has three bitor'ed elements. Default indicates that
'  default binding rules should be applied.
t.InvokeMember ("SayHello", _
BindingFlags.Default BitOr BindingFlags.InvokeMethod _
BitOr BindingFlags.Static, nothing, _
nothing, new object () {})
End Sub
End Class

C# VB
快速查看一下传递给 Invoke 方法的其余参数。传递的第一个空参数请求使用默认联编程序绑定正在调用的方法。当调用默认联编程序时,请包含默认的 BindingFlags。第三个参数可以不为空,您可以指定一个 Binder 对象,它定义一组属性并启用绑定,这可能涉及选择重载方法或强制参数类型。第二个空参数是您在其上调用所选方法的对象。最后,传递由成员接收的参数对象数组。在本例中,SayHello 方法不接收任何参数,因此传递一个空数组。

下面的情况略有不同。调用名为 ComputeSum 的另一个静态方法,但是在此情况下,此方法需要两个参数。因此,用这些参数填充一个对象数组,并将它们作为最后一个参数传递到 InvokeMember 中。

// Calling a static method, which needs arguments
object [] args = new object [] {100.09, 184.45};

// we know that this particular method returns a value, being the computed sum,
// so we create a variable to hold the return
// note the datatype of the return is object, the only datatype InvokeMethod returns...
object result;

// invoke the method. Note the change in the last parameter: the array we populated...
result = t.InvokeMember ("ComputeSum", BindingFlags.Default | _
BindingFlags.InvokeMethod | BindingFlags.Static,
null, null, args);

// write the results to the user's console...
Console.WriteLine ("{0} + {1} = {2}", args[0], args[1], result);

'  Calling a static method, which needs arguments
Dim args as object ()
args = new object () {100.09, 184.45}

'  we know that this particular method returns a value, being the computed sum,
'  so we create a variable to hold the return
'  note the datatype of the return is object, the only datatype InvokeMethod returns...
Dim result As object

'  invoke the method. Note the change in the last parameter: the array we populated...
result = t.InvokeMember ("ComputeSum", BindingFlags.Default BitOr _
BindingFlags.InvokeMethod BitOr BindingFlags.Static, _
nothing, nothing, args)

'  write the results to the user's console...
Console.WriteLine ("{0} + {1} = {2}", args(0), args(1), result)

C# VB
在前两个示例中,已调用了静态方法。还可以调用实例方法。若要这样做,将您要在其上调用方法的类型的对象作为第三个参数传递。本示例还展示为了使用 InvokeMember,您不必有实际的 Type 对象。在此情况下,通常将希望使用所拥有的类实例来调用 GetType,如下面的示例所示。注意由于未调用静态方法,所以 BindingFlags 已更改。
// Calling  an instance method
// we need an object reference to invoke an instance member
TestClass c = new TestClass ();

// use the instance of our class to call GetType
// we no longer include the Static element in BindingFlags for our |
// the fourth parameter is no longer null: we instead pass an instance
// of the object we wish to invoke our method on
c.GetType().InvokeMember ("AddUp", BindingFlags.Default | BindingFlags.InvokeMethod,
null, c, new object [] {});
c.GetType().InvokeMember ("AddUp", BindingFlags.Default | BindingFlags.InvokeMethod,
null, c, new object [] {});

'  Calling  an instance method
'  we need an object reference to invoke an instance member
Dim c as TestClass
c = new TestClass ()

'  use the instance of our class to call GetType
'  we no longer include the Static element in BindingFlags for our bitor
'  the fourth parameter is no longer null: we instead pass an instance
'  of the object we wish to invoke our method on
c.GetType().InvokeMember ("AddUp", BindingFlags.Default BitOr BindingFlags.InvokeMethod, _
nothing, c, new object () {})
c.GetType().InvokeMember ("AddUp", BindingFlags.Default BitOr BindingFlags.InvokeMethod, _
nothing, c, new object () {})

C# VB
有时不想调用方法,而需要调用其他成员,如属性或字段。若要实现它,只需更改 BindingFlags 组合(而不是 InvokeMethod)以包含适当元素即可。下面的示例展示获取和设置字段值。所讨论字段不是静态字段,因此需要创建一个对象实例来请求该字段。设置字段值时,需要将所设置的值作为对象数组参数的唯一元素传递。获取值时,需要将 InvokeMember 方法的返回类型分配给一个对象。
// Setting a field. Assume we are using the same Type and Class declared in the
// previous examples (t and c). The field we are setting is the Name field
// note the BindingFlags argument now includes SetField rather thanInvokeMember
// Further, this is an instance field, so we pass the instance of our class
t.InvokeMember ("Name", BindingFlags.Default | BindingFlags.SetField,
null, c, new object [] {"NewName"});

// similar usage...
result = t.InvokeMember ("Name", BindingFlags.Default | BindingFlags.GetField,
null, c, new object [] {});

Console.WriteLine ("Name == {0}", result);

'  Setting a field. Assume we are using the same Type and Class declared in the
'  previous examples (t and c). The field we are setting is the Name field
'  note the BindingFlags argument now includes SetField rather thanInvokeMember
'  Further, this is an instance field, so we pass the instance of our class
t.InvokeMember ("Name", BindingFlags.Default BitOr BindingFlags.SetField, _
nothing, c, new object () {"NewName"})

'  similar usage...
result = t.InvokeMember ("Name", BindingFlags.Default BitOr BindingFlags.GetField, _
nothing, c, new object () {})

Console.WriteLine ("Name == {0}", result)

C# VB
还可以获取和设置属性,但在本示例中,假定所设置属性是一个具有多个元素的数组或集合。若要指定特定元素的设置,您需要指定索引。若要设置属性,请分配 BindingFlags.SetProperty。若要指定属性的集合索引或数组索引,请将要设置元素的索引值放在对象数组的第一个元素中,然后将要设置的值作为第二个元素。若要取回该属性,请将索引作为对象数组中的唯一元素传递,指定 BindingFlags.GetProperty。

// Set an indexed property value
int index = 3;

// specify BindingFlags.SetProperty, and because this is an instance property,
// pass the object to call the property on (c). In the object array, make two elements,
// the first being the index, and the second being the value to set
t.InvokeMember ("Item", BindingFlags.Default |BindingFlags.SetProperty,
null, c, new object [] {index, "NewValue"});

// Get an indexed property value
// specify BindingFlags.GetProperty, and because this is an instance property,
// pass the object to call the property on (c). In the object array, specify the index only
result = t.InvokeMember ("Item", BindingFlags.Default |BindingFlags.GetProperty,
null, c, new object [] {index});

Console.WriteLine ("Item[{0}] == {1}", index, result);

' Set an indexed property value
Dim  index As Int32 = 3

'  specify BindingFlags.SetProperty, and because this is an instance property,
'  pass the object to call the property on (c). In the object array, make two elements,
'  the first being the index, and the second being the value to set
t.InvokeMember ("Item", BindingFlags.Default BitOr BindingFlags.SetProperty, _
nothing, c, new object () {index, "NewValue"})

'  Get an indexed property value
'  specify BindingFlags.GetProperty, and because this is an instance property,
'  pass the object to call the property on (c). In the object array, specify the index only
result = t.InvokeMember ("Item", BindingFlags.Default BitOr BindingFlags.GetProperty, _
nothing, c, new object () {index})

Console.WriteLine ("Item[{0}] == {1}", index, result)

C# VB
还可以使用命名参数,在此情况下需要使用 InvokeMember 方法的另一个重载版本。像迄今一直进行的那样创建对象参数的数组,并创建所传递参数的名称的字符串数组。您要使用的重载方法接受参数名列表作为最后一个参数,并接受要设置的值的列表作为第五个参数。在本演示中,所有其他参数都可以为空(当然前两个除外)。

// Calling a method using named arguments

// the argument array, and the parameter name array. Obviously, you will need
// to determine the names of the parameters in advance
object[] argValues = new object [] {"Mouse", "Micky"};
String [] argNames = new String [] {"lastName", "firstName"};

// the first five parameters for this overloaded method are the same as the
// the five parameters we have used to this point. The final parameter needs to be
// set to the names of the parameters
t.InvokeMember ("PrintName", BindingFlags.Default | BindingFlags.InvokeMethod,
null, null, argValues, null, null, argNames);

'  Calling a method using named arguments

'  the argument array, and the parameter name array. Obviously, you will need
'  to determine the names of the parameters in advance
object[] argValues = new object [] {"Mouse", "Micky"};
String [] argNames = new String [] {"lastName", "firstName"};

'  the first five parameters for this overloaded method are the same as the
'  the five parameters we have used to this point. The final parameter needs to be
'  set to the names of the parameters
t.InvokeMember ("PrintName", BindingFlags.Default BitOr BindingFlags.InvokeMethod, _
nothing, nothing, argValues, nothing, nothing, argNames)

C# VB
下一个示例展示如何调用类上的默认成员。确保在其上进行调用的类指定有默认成员。然后在 InvokeMember 方法中,不要指定要调用成员的名称,如本示例所示。

// our class with it's default member specified, using the defaultmemeber attribute
[DefaultMemberAttribute ("PrintTime")]
public class TestClass2 {

public void PrintTime () {
Console.WriteLine (DateTime.Now);
}
}

// the client code that uses the above class...

Type t3 = typeof (TestClass2);
t3.InvokeMember ("", BindingFlags.Default |BindingFlags.InvokeMethod,
null, new TestClass2(), new object [] {});

'  our class with it's default member specified, using the defaultmemeber attribute

public  class  TestClass2

public Sub PrintTime ()
Console.WriteLine (DateTime.Now)
End Sub
End Class

'  the client code that uses the above class...
Dim t3 As Type

t3 = GetType (TestClass2)
t3.InvokeMember ("", BindingFlags.Default  BitOr BindingFlags.InvokeMethod, _
nothing, new TestClass2(), new object () {})

C# VB
最后一个示例使用略有不同的过程调用方法。不直接使用 Type 对象,而是直接创建一个单独的 MethodInfo 对象来表示将调用的方法。然后调用 MethodInfo 对象上的 Invoke 方法,传递需要在其上调用方法的对象的实例(在要调用实例方法的情况下,但是,如果方法是静态的,则为空)。像以前一样,需要参数的对象数组。如果需要,该特定示例允许您通过引用传递参数。

// Invoking a ByRef member
MethodInfo m = t.GetMethod("Swap");

args = new object[2];
args[0] = 1;
args[1] = 2;

m.Invoke(new TestClass(),args);

Console.WriteLine ("{0}, {1}", args[0], args[1]);

'  Invoking a ByRef member
Dim m as MethodInfo =
m = t.GetMethod("Swap")

args = new object() {CObj(1), CObj(2)}

m.Invoke(new TestClass(),args)

Console.WriteLine ("{0}, {1}", args(0), args(1))

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: