



















反射提供语言编译器(如 Microsoft Visual Basic 2005 和 JScript)用于实现隐式后期绑定的基础结构。绑定是查找与唯一指定的类型相对应的声明(即实现)的过程。如果此过程是在运行时而不是在编译时发生,则称其为“后期绑定”。利用 Visual Basic 2005,可以在代码中使用隐式后期绑定;Visual Basic 编译器会调用一个帮助器方法,该方法使用反射来获取对象类型。传递给帮助器方法的参数有助于在运行时调用正确的方法。这些参数包括:对其调用方法的实例(对象),被调用方法的名称(字符串),以及传递给被调用方法的参数(对象数组)。
在下面的示例中,Visual Basic 编译器使用反射隐式地对其类型在编译时未知的对象调用方法。HelloWorld 类具有一个 PrintHello 方法,它输出与传递给 PrintHello 方法的某些文本串联的“Hello World”。在此示例中调用的 PrintHello 方法实际上是 Type..::.InvokeMember;Visual Basic 代码允许按照对象 (helloObj) 的类型在编译时已知(早期绑定)而不是在运行时已知(后期绑定)的方式来调用 PrintHello 方法。
Imports System
Module Hello
Sub Main()
' Sets up the variable.
Dim helloObj As Object
' Creates the object.
helloObj = new HelloWorld()
' Invokes the print method as if it was early bound
' even though it is really late bound.
helloObj.PrintHello("Visual Basic Late Bound")
End Sub
End Module

除了由编译器隐式地用来进行后期绑定之外,反射还可以在代码中显式地用来完成后期绑定。公共语言运行库支持多种编程语言,但这些语言的绑定规则各不相同。在早期绑定的情况下,代码生成器可以完全控制此绑定。但是,当通过反射进行后期绑定时,必须用自定义绑定来控制绑定。Binder 类提供了对成员选择和调用的自定义控制。利用自定义绑定,您可以在运行时加载程序集,获取有关该程序集中类型的信息,然后对该类型调用方法或访问该类型的字段或属性。如果您在编译时(例如当对象类型依赖于用户输入时)不知道对象的类型,就可以使用这种方法。下面的示例说明不提供参数类型转换的简单的自定义联编程序。Simple_Type.dll 的代码位于示例主体之前。确保生成 Simple_Type.dll,然后在生成时在项目中包括对它的引用。
// Code for building SimpleType.dll.
using System;

namespace Simple_Type
{
public class MySimpleClass
{
public void MyMethod(string str, int i)
{
Console.WriteLine("MyMethod parameters: {0}, {1}", str, i);
}

public void MyMethod(string str, int i, int j)
{
Console.WriteLine("MyMethod parameters: {0}, {1}, {2}",
str, i, j);
}
}
}


using System;
using System.Reflection;
using System.Globalization;
using Simple_Type;
namespace Custom_Binder
{
class MyMainClass
{
static void Main()
{
// Get the type of MySimpleClass.
Type myType = typeof(MySimpleClass);

// Get an instance of MySimpleClass.
MySimpleClass myInstance = new MySimpleClass();
MyCustomBinder myCustomBinder = new MyCustomBinder();

// Get the method information for the particular overload
// being sought.
MethodInfo myMethod = myType.GetMethod("MyMethod",
BindingFlags.Public | BindingFlags.Instance,
myCustomBinder, new Type[] {typeof(string),
typeof(int)}, null);
Console.WriteLine(myMethod.ToString());
// Invoke the overload.
myType.InvokeMember("MyMethod", BindingFlags.InvokeMethod,
myCustomBinder, myInstance,
new Object[] {"Testing
", (int)32});
}
}

//****************************************************
// A simple custom binder that provides no
// argument type conversion.
//****************************************************
class MyCustomBinder : Binder
{
public override MethodBase BindToMethod(
BindingFlags bindingAttr,
MethodBase[] match,
ref object[] args,
ParameterModifier[] modifiers,
CultureInfo culture,
string[] names,
out object state)
{
if(match == null)
throw new ArgumentNullException("match");
// Arguments are not being reordered.
state = null;
// Find a parameter match and return the first method with
// parameters that match the request.
foreach(MethodBase mb in match)
{
ParameterInfo[] parameters = mb.GetParameters();

if(ParametersMatch(parameters, args))
return mb;
}
return null;
}

public override FieldInfo BindToField(BindingFlags bindingAttr,
FieldInfo[] match, object value, CultureInfo culture)
{
if(match == null)
throw new ArgumentNullException("match");
foreach(FieldInfo fi in match)
{
if(fi.GetType() == value.GetType())
return fi;
}
return null;
}

public override MethodBase SelectMethod(
BindingFlags bindingAttr,
MethodBase[] match,
Type[] types,
ParameterModifier[] modifiers)
{
if(match == null)
throw new ArgumentNullException("match");

// Find a parameter match and return the first method with
// parameters that match the request.
foreach(MethodBase mb in match)
{
ParameterInfo[] parameters = mb.GetParameters();
if(ParametersMatch(parameters, types))
return mb;
}

return null;
}

public override PropertyInfo SelectProperty(
BindingFlags bindingAttr,
PropertyInfo[] match,
Type returnType,
Type[] indexes,
ParameterModifier[] modifiers)
{
if(match == null)
throw new ArgumentNullException("match");
foreach(PropertyInfo pi in match)
{
if(pi.GetType() == returnType &&
ParametersMatch(pi.GetIndexParameters(), indexes))
return pi;
}
return null;
}

public override object ChangeType(
object value,
Type myChangeType,
CultureInfo culture)
{
try
{
object newType;
newType = Convert.ChangeType(value, myChangeType);
return newType;
}
// Throw an InvalidCastException if the conversion cannot
// be done by the Convert.ChangeType method.
catch(InvalidCastException)
{
return null;
}
}

public override void ReorderArgumentArray(ref object[] args,
object state)
{
// No operation is needed here because BindToMethod does not
// reorder the args array. The most common implementation
// of this method is shown below.
// ((BinderState)state).args.CopyTo(args, 0);
}

// Returns true only if the type of each object in a matches
// the type of each corresponding object in b.
private bool ParametersMatch(ParameterInfo[] a, object[] b)
{
if(a.Length != b.Length)
return false;
for(int i = 0; i < a.Length; i++)
{
if(a[i].ParameterType != b[i].GetType())
return false;
}
return true;
}

// Returns true only if the type of each object in a matches
// the type of each corresponding entry in b.
private bool ParametersMatch(ParameterInfo[] a, Type[] b)
{
if(a.Length != b.Length)
return false;
for(int i = 0; i < a.Length; i++)
{
if(a[i].ParameterType != b[i])
return false;
}
return true;
}
}
}
InvokeMember 和 CreateInstance
使用 Type.InvokeMember 可调用类型的成员。各个类(如 System.Activator 和 System.Reflection.Assembly)的 CreateInstance 方法是 InvokeMember 的特殊形式,它们可新建特定类型的实例。Binder 类用于在这些方法中进行重载决策和参数强制。
下面的示例显示参数强制(类型转换)和成员选择的三种可能的组合。在第 1 种情况中,不需要任何参数强制或成员选择。在第 2 种情况中,只需要成员选择。在第 3 种情况中,只需要参数强制
public class CustomBinderDriver
{
public static void Main (string[] arguments)
{
Type t = typeof (CustomBinderDriver);
CustomBinder binder = new CustomBinder();
BindingFlags flags = BindingFlags.InvokeMethod|BindingFlags.Instance|
BindingFlags.Public|BindingFlags.Static;

// Case 1. Neither argument coercion nor member selection is needed.
args = new Object[] {};
t.InvokeMember ("PrintBob", flags, binder, null, args);

// Case 2. Only member selection is needed.
args = new Object[] {42};
t.InvokeMember ("PrintValue", flags, binder, null, args);

// Case 3. Only argument coercion is needed.
args = new Object[] {"5.5"};
t.InvokeMember ("PrintNumber", flags, binder, null, args);
}

public static void PrintBob ()
{
Console.WriteLine ("PrintBob");
}

public static void PrintValue (long value)
{
Console.WriteLine ("PrintValue ({0})", value);
}
public static void PrintValue (String value)
{
Console.WriteLine ("PrintValue\"{0}\")", value);
}
public static void PrintNumber (double value)
{
Console.WriteLine ("PrintNumber ({0})", value);
}
}
|
源类型 |
目标类型 |
|---|---|
|
任何类型 |
它的基类型 |
|
任何类型 |
它所实现的接口 |
|
Char |
UInt16、UInt32、Int32、UInt64、Int64、Single、Double |
|
Byte |
Char、UInt16、Int16、UInt32、Int32、UInt64、Int64、Single、Double |
|
SByte |
Int16、Int32、Int64、Single、Double |
|
UInt16 |
UInt32、Int32、UInt64、Int64、Single、Double |
|
Int16 |
Int32、Int64、Single、Double |
|
UInt32 |
UInt64、Int64、Single、Double |
|
Int32 |
Int64、Single、Double |
|
UInt64 |
Single、Double |
|
Int64 |
Single、Double |
|
Single |
Double |
|
非引用类型 |
引用类型 |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。