您的位置:首页 > 其它

反射-动态加载和使用类型

2008-09-26 12:07 387 查看
1反射提供语言编译器(如 Microsoft Visual Basic 2005 和 JScript)用于实现隐式后期绑定的基础结构。绑定是查找与唯一指定的类型相对应的声明(即实现)的过程。如果此过程是在运行时而不是在编译时发生,则称其为“后期绑定”。利用 Visual Basic 2005,可以在代码中使用隐式后期绑定;Visual Basic 编译器会调用一个帮助器方法,该方法使用反射来获取对象类型。传递给帮助器方法的参数有助于在运行时调用正确的方法。这些参数包括:对其调用方法的实例(对象),被调用方法的名称(字符串),以及传递给被调用方法的参数(对象数组)。

2

3在下面的示例中,Visual Basic 编译器使用反射隐式地对其类型在编译时未知的对象调用方法。HelloWorld 类具有一个 PrintHello 方法,它输出与传递给 PrintHello 方法的某些文本串联的“Hello World”。在此示例中调用的 PrintHello 方法实际上是 Type..::.InvokeMember;Visual Basic 代码允许按照对象 (helloObj) 的类型在编译时已知(早期绑定)而不是在运行时已知(后期绑定)的方式来调用 PrintHello 方法。

4

5 复制代码

6Imports System

7Module Hello

8 Sub Main()

9 ' Sets up the variable.

10 Dim helloObj As Object

11 ' Creates the object.

12 helloObj = new HelloWorld()

13 ' Invokes the print method as if it was early bound

14 ' even though it is really late bound.

15 helloObj.PrintHello("Visual Basic Late Bound")

16 End Sub

17End Module

18

19

20自定义绑定

21除了由编译器隐式地用来进行后期绑定之外,反射还可以在代码中显式地用来完成后期绑定。

22

23公共语言运行库支持多种编程语言,但这些语言的绑定规则各不相同。在早期绑定的情况下,代码生成器可以完全控制此绑定。但是,当通过反射进行后期绑定时,必须用自定义绑定来控制绑定。Binder 类提供了对成员选择和调用的自定义控制。

24

25利用自定义绑定,您可以在运行时加载程序集,获取有关该程序集中类型的信息,然后对该类型调用方法或访问该类型的字段或属性。如果您在编译时(例如当对象类型依赖于用户输入时)不知道对象的类型,就可以使用这种方法。

26

27下面的示例说明不提供参数类型转换的简单的自定义联编程序。Simple_Type.dll 的代码位于示例主体之前。确保生成 Simple_Type.dll,然后在生成时在项目中包括对它的引用。

28

29Visual Basic 复制代码

30' Code for building Simple_Type.dll.

31Imports System

32

33Namespace Simple_Type

34 Public Class MySimpleClass

35 Public Overloads Sub MyMethod(ByVal str As String,

36 ByVal i As Integer)

37 Console.WriteLine("MyMethod parameters: {0}, {1}", str, i)

38 End Sub 'MyMethod

39

40 Public Overloads Sub MyMethod(ByVal str As String,

41 ByVal i As Integer, ByVal j As Integer)

42 Console.WriteLine("MyMethod parameters: {0}, {1}, {2}", str,

43 i, j)

44 End Sub 'MyMethod

45 End Class 'MySimpleClass

46End Namespace 'Simple_Type

47

48Imports System

49Imports System.Reflection

50Imports System.Globalization

51Imports Simple_Type.Simple_Type

52

53Namespace Custom_Binder

54 Class MyMainClass

55 Shared Sub Main()

56 ' Get the type of MySimpleClass.

57 Dim myType As Type = GetType(MySimpleClass)

58 ' Get an instance of MySimpleClass.

59 Dim myInstance As New MySimpleClass()

60 Dim myCustomBinder As New MyCustomBinder()

61 ' Get the method information for the overload being sought.

62 Dim myMethod As MethodInfo = myType.GetMethod("MyMethod",

63 BindingFlags.Public Or BindingFlags.Instance,

64 Console.WriteLine(myMethod.ToString())

67 ' Invoke the overload.

68 myType.InvokeMember("MyMethod", BindingFlags.InvokeMethod,

69 myCustomBinder, myInstance,

70 End Sub 'Main

72 End Class 'MyMainClass

73

74 '****************************************************

75 ' A simple custom binder that provides no

76 ' argument type conversion.

77 '****************************************************

78 Class MyCustomBinder

79 Inherits Binder

80

81 Public Overrides Function BindToMethod(ByVal bindingAttr As

82 BindingFlags, ByVal match() As MethodBase, ByRef args() As

83 Object, ByVal modifiers() As ParameterModifier, ByVal

84 culture As CultureInfo, ByVal names() As String, ByRef

85 state As Object) As MethodBase

86 If match Is Nothing Then

87 Throw New ArgumentNullException("match")

88 End If

89 ' Arguments are not being reordered.

90 state = Nothing

91 ' Find a parameter match and return the first method with

92 ' parameters that match the request.

93 Dim mb As MethodBase

94 For Each mb In match

95 Dim parameters As ParameterInfo() = mb.GetParameters()

96 If ParametersMatch(parameters, args) Then

97 Return mb

98 End If

99 Next mb

100 Return Nothing

101 End Function 'BindToMethod

102

103 Public Overrides Function BindToField(ByVal bindingAttr As

104 BindingFlags, ByVal match() As FieldInfo, ByVal value As

105 Object, ByVal culture As CultureInfo) As FieldInfo

106 If match Is Nothing Then

107 Throw New ArgumentNullException("match")

108 End If

109 Dim fi As FieldInfo

110 For Each fi In match

111 If fi.GetType() Is value.GetType() Then

112 Return fi

113 End If

114 Next fi

115 Return Nothing

116 End Function 'BindToField

117

118 Public Overrides Function SelectMethod(ByVal bindingAttr As

119 BindingFlags, ByVal match() As MethodBase, ByVal types() As

120 Type, ByVal modifiers() As ParameterModifier) As

121 MethodBase

122 If match Is Nothing Then

123 Throw New ArgumentNullException("match")

124 End If

125 ' Find a parameter match and return the first method with

126 ' parameters that match the request.

127 Dim mb As MethodBase

128 For Each mb In match

129 Dim parameters As ParameterInfo() = mb.GetParameters()

130 If ParametersMatch(parameters, types) Then

131 Return mb

132 End If

133 Next mb

134 Return Nothing

135 End Function 'SelectMethod

136

137 Public Overrides Function SelectProperty(ByVal bindingAttr As

138 BindingFlags, ByVal match() As PropertyInfo, ByVal returnType

139 As Type, ByVal indexes() As Type, ByVal modifiers() As

140 ParameterModifier) As PropertyInfo

141 If match Is Nothing Then

142 Throw New ArgumentNullException("match")

143 End If

144 Dim pi As PropertyInfo

145 For Each pi In match

146 If pi.GetType() Is returnType And

147 ParametersMatch(pi.GetIndexParameters(), indexes) Then

148 Return pi

149 End If

150 Next pi

151 Return Nothing

152 End Function 'SelectProperty

153

154 Public Overrides Function ChangeType(ByVal value As Object,

155 ByVal myChangeType As Type, ByVal culture As CultureInfo)

156 As Object

157 Try

158 Dim newType As Object

159 newType = Convert.ChangeType(value, myChangeType)

160

161 Return newType

162 ' Throw an InvalidCastException if the conversion cannot

163 ' be done by the Convert.ChangeType method.

164 Catch

165 End Try

166 End Function 'ChangeType

167

168 Public Overrides Sub ReorderArgumentArray(ByRef args() As Object,

169 ByVal state As Object)

170 ' No operation is needed here because BindToMethod does not

171 ' reorder the args array. The most common implementation

172 ' of this method is shown below.

173

174 ' ((BinderState)state).args.CopyTo(args, 0);

175 End Sub 'ReorderArgumentArray

176

177 ' Returns true only if the type of each object in a matches

178 ' the type of each corresponding object in b.

179 Private Overloads Function ParametersMatch(ByVal a() As

180 ParameterInfo, ByVal b() As Object) As Boolean

181 If a.Length <> b.Length Then

182 Return False

183 End If

184 Dim i As Integer

185 For i = 0 To a.Length - 1

186 If Not (a(i).ParameterType Is b(i).GetType()) Then

187 Return False

188 End If

189 Next i

190 Return True

191 End Function 'ParametersMatch

192

193 ' Returns true only if the type of each object in a matches

194 ' the type of each corresponding entry in b.

195 Private Overloads Function ParametersMatch(ByVal a() As

196 ParameterInfo, ByVal b() As Type) As Boolean

197 If a.Length <> b.Length Then

198 Return False

199 End If

200 Dim i As Integer

201 For i = 0 To a.Length - 1

202 If Not (a(i).ParameterType Is b(i)) Then

203 Return False

204 End If

205 Next i

206 Return True

207 End Function 'ParametersMatch

208 End Class 'MyCustomBinder

209End Namespace 'Custom_Binder

210

211

212

213

214C# 复制代码

215// Code for building SimpleType.dll.

216using System;

217

218namespace Simple_Type

219

235

236using System;

237using System.Reflection;

238using System.Globalization;

239using Simple_Type;

240namespace Custom_Binder

241

410

411InvokeMember 和 CreateInstance

412使用 Type..::.InvokeMember 可调用类型的成员。各个类(如 System.Activator 和 System.Reflection.Assembly)的 CreateInstance 方法是 InvokeMember 的特殊形式,它们可新建特定类型的实例。Binder 类用于在这些方法中进行重载决策和参数强制。

413

414下面的示例显示参数强制(类型转换)和成员选择的三种可能的组合。在第 1 种情况中,不需要任何参数强制或成员选择。在第 2 种情况中,只需要成员选择。在第 3 种情况中,只需要参数强制。

415

416C# 复制代码

417public class CustomBinderDriver

418

459

460当多个成员具有相同的名称时,将需要重载决策。Binder..::.BindToMethod 和 Binder..::.BindToField 方法用于解析与单个成员的绑定。Binder.BindToMethod 还通过 get 和 set 属性访问器提供了属性解析。

461

462BindToMethod 返回要调用的 MethodBase;如果无法进行这种调用,则返回 null 引用(在 Visual Basic 中为 Nothing)。虽然 MethodBase 返回值通常是 match 参数中所包含的值之一,但它并不必如此。

463

464当存在 ByRef 参数时,调用方可能需要取回这些参数。因此,如果 BindToMethod 已经操作参数数组,Binder 会允许客户端将参数数组映射回它的初始形式。为了实现这一目的,必须向调用方保证参数的顺序不会改变。当按名称传递参数时,Binder 将重新排列参数数组,这就是调用方所见的参数。有关更多信息,请参见 Binder..::.ReorderArgumentArray。

465

466可用成员集包括在类型和任何基类型中定义的成员。如果指定 BindingFlags.NonPublic,将返回该成员集中具有任何可访问性的成员。如果未指定 BindingFlags.NonPublic,联编程序就必须强制可访问性规则。当指定 Public 或 NonPublic 绑定标志时,还必须指定 Instance 或 Static 绑定标志,否则不会返回任何成员。

467

468如果只有一个成员具有给定名称,则不必进行回调,而在该方法上进行绑定。代码示例的第 1 种情况说明了这一点:只有一个 PrintBob 方法可用,因此不需要进行回调。

469

470如果可用集中有多个成员,所有这些方法都将传递给 BindToMethod,它将选择正确的方法并将其返回。在代码示例的第 2 种情况下,有两个名为 PrintValue 的方法。对 BindToMethod 的调用将选择正确的方法。

471

472ChangeType 执行参数强制转换(类型转换),以便将实参转换为选定方法的形参的类型。即使类型完全匹配,也会为每个参数调用 ChangeType。

473

474在代码示例的第 3 种情况下,将类型为 String 值为“5.5”的实参传递给了具有类型为 Double 的形参的方法。要使调用成功,必须将字符串值“5.5”转换为 double 值。ChangeType 会执行此转换。

475

476ChangeType 仅执行无损或扩大强制,如下表所示。

477

478源类型

479 目标类型

480

481任何类型

482 它的基类型

483

484任何类型

485 它所实现的接口

486

487Char

488 UInt16、UInt32、Int32、UInt64、Int64、Single、Double

489

490Byte

491 Char、UInt16、Int16、UInt32、Int32、UInt64、Int64、Single、Double

492

493SByte

494 Int16、Int32、Int64、Single、Double

495

496UInt16

497 UInt32、Int32、UInt64、Int64、Single、Double

498

499Int16

500 Int32、Int64、Single、Double

501

502UInt32

503 UInt64、Int64、Single、Double

504

505Int32

506 Int64、Single、Double

507

508UInt64

509 Single、Double

510

511Int64

512 Single、Double

513

514Single

515 Double

516

517非引用类型

518 引用类型

519

520

521Type 类具有 Get 方法,这些方法使用 Binder 类型的参数来解析对特定成员的引用。Type..::.GetConstructor、Type..::.GetMethod 和 Type..::.GetProperty 通过为当前类型的特定成员提供签名信息来搜索该成员。对 Binder..::.SelectMethod 和 Binder..::.SelectProperty 进行回调以选择相应方法的给定签名信息。

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