?? simplebinder.cs
字號:
/******************************************************************************
Module: SimpleBinder.cs
Notices: Copyright (c) 2002 Jeffrey Richter
Thanks: To Dario Russi for supplying the initial version of this code.
******************************************************************************/
using System;
using System.Reflection;
using System.Collections;
using CultureInfo = System.Globalization.CultureInfo;
///////////////////////////////////////////////////////////////////////////////
public sealed class SimpleBinder : Binder {
// Type.InvokeMember calls this method if more than 1 field matches.
// This code performs uses simple conversion rules to bind.
public override FieldInfo BindToField(
BindingFlags bindingAttr, // Flags to restrict options
FieldInfo[] fields, // Field subset selected by reflection
Object value, // The value to set
CultureInfo culture) { // Culture (usually ignored)
// Get the type of the value that is to be assigned to the field
Type valueType = value.GetType();
// If any fields exactly match the value's type, return that field
foreach (FieldInfo f in fields)
if (valueType == f.FieldType) return f;
// If any fields have a "compatible" type, return that field
foreach (FieldInfo f in fields) {
// Get the type of the field
Type formalType = f.FieldType;
// If the value's type is compatible with the field's type, return it
if (CanConvertPrimitiveType(valueType, formalType)) return f;
// Consider a match if the value can be assigned to the field's type
if (!formalType.IsValueType) {
// It must be some sort of "compatible" reference type
if (formalType.IsAssignableFrom(valueType)) return f;
}
}
// No compatible field was found
throw new MissingFieldException("Field not found.");
}
// Type.InvokeMember and Activator.CreateInstance call this method to
// select a specific method.
// This code performs uses simple conversion rules to bind.
public override MethodBase BindToMethod(
BindingFlags bindingAttr, // Flags to restrict options
MethodBase[] methods, // Method subset selected by reflection
ref Object[] args, // Arguments provided by the caller
// (BindToMethod can modify this array)
ParameterModifier[] modifiers, // Modifiers (usually ignored)
CultureInfo culture, // Culture (usually ignored)
String[] names, // Named arguments (if any)
out Object state) { // If 'args' is changed, this object can
// be used to get back the original
// array by calling ReorderArgumentArray
// This binder doesn't support argument re-ordering
state = null;
// Construct array of method argument types.
Type[] argType = new Type[args.Length];
for (Int32 i = 0; i < args.Length; i++) {
if (args[i] != null) {
argType[i] = args[i].GetType();
}
}
// A more sophisticated binder would have code here to deal with methods
// that accept a variable number of arguments (ParamArrayAttribute) and
// with methods that accept optional arguments and named parameters.
// Select a method that matches type argument's types.
return SelectMethod(bindingAttr, methods, argType, modifiers);
}
// Flags indicating how to compare the specified argument types
// with the method's parameter types.
[Flags]
private enum CompareParamAndArgTypesFlags {
Exact = 0x0000,
CoerceValueTypes = 0x0001,
AllowBaseTypes = 0x0002,
}
// This method returns true if the specified argument types match
// the method's parameter types
private static Boolean CompareParamAndArgTypes(
ParameterInfo[] paramTypes,
Type[] argTypes,
CompareParamAndArgTypesFlags flags) {
// This binder requires that the number of arguments and parameters match
if (paramTypes.Length != argTypes.Length) return false;
Int32 i = 0;
for (; i < paramTypes.Length; i++) {
// If the argument has a type, compare it against the parameter's type
// This can be null if Type.InvokeMember is passed null for an argument
if (argTypes[i] != null) {
Type formalType = paramTypes[i].ParameterType;
// If argument and parameter types match exactly, try next pair
if (formalType == argTypes[i]) continue;
// Compare the primitive, value type, or enumerated type parameter
if (formalType.IsValueType) {
if (((flags & CompareParamAndArgTypesFlags.CoerceValueTypes) != 0) &&
CanConvertPrimitiveType(argTypes[i], formalType)) continue;
break; // Can't coerce argument type to parameter type
} else {
// Compare the reference type parameter
if (((flags & CompareParamAndArgTypesFlags.AllowBaseTypes) != 0) &&
formalType.IsAssignableFrom(argTypes[i])) continue;
break; // Can't implicitly cast argument type to parameter type
}
}
}
// Return true if all argument and parameter types match
return (i == paramTypes.Length);
}
// Called to change a type during invocation.
// There must have been a type mismatch and we are asked to intervene.
public override Object ChangeType(Object value, Type type, CultureInfo culture) {
// We only do primitive conversions.
if (CanConvertPrimitiveType(value.GetType(), type)) {
return DoConvertPrimitiveType(value, type);
}
throw new ArgumentException("No conversion allowed for one of the arguments");
}
// Called to restore the args array back to that passed to BindToMethod.
// This code does nothing because we don't handle named or optional arguments
public override void ReorderArgumentArray(
ref Object[] args, // Arguments provided by the caller
Object state) { // This object can is used to get back
// the original array
// Here's the scenario where this method comes in useful...
// Say InvokeMember is called passing some named arguments. The elements
// in this array must be reordered so that arguments are in the correct
// position before invoking the method. For optional arguments, the
// array must grow to accommodate the unspecified arguments.
// Note: If an argument is marked as 'out' or 'ref', the return value
// will be updated in this array. These array element values must be
// copied back to the reflection caller's original array so that they
// can get the 'returned' values.
// For example, let's say that Class Foo defines the following method:
// class Foo {
// public static void m(Int32 i, ref Object o) { ... }
// }
// Now, let's invoke this method using a named parameter as follows:
// Object[] args = new Object[] { obj, 3 };
// typeof(Foo).InvokeMember("m",
// BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
// new SimpleBinder(), // The binder
// null, // No object; static method
// args, // The arguments to pass (Object followed by Int32)
// null, // No ParamterModifier array
// null, // No Culture
// new String[] {"o"}); // The first argument should be the 'o' parameter
// Notice the Object and Int32 arguments are passed in reverse order.
// This is OK if the binder can deal with named parameters.
// In BindToMethod, the argument array must be reordered in order to
// sucessfully invoke the method. This array can't be returned to the
// caller since the caller would have no knowledge what was where.
// Also, the caller needs to fetch the 'ref' value out of the array.
// This ReorderArgumentArray method must transform the array used to
// invoke the method back to the array expected by the caller.
// BindToMethod should save any information required to restore the
// argument array in the state parameter passed to this method.
}
// GetMethod calls this method to select a specific method.
// This code performs uses simple conversion rules to bind.
public override MethodBase SelectMethod(
BindingFlags bindingAttr, // Flags to restrict options
MethodBase[] methods, // Method subset selected by reflection
Type[] argTypes, // Set of argument types
ParameterModifier[] modifiers) { // Modifiers (usually ignored)
// This ArrayList contains the set of possible methods
ArrayList candidates = new ArrayList();
// Build the set of candidate methods removing any method that
// doesn't have the specified number of arguments.
// A more sophisticated binder would have code here to deal with methods
// that accept a variable number of arguments (ParamArrayAttribute) and
// with methods that accept optional arguments and named parameters.
Int32 argCount = argTypes.Length;
foreach (MethodBase m in methods) {
if (m.GetParameters().Length == argCount)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -