📄 simplebinder.cs
字号:
candidates.Add(m);
}
// If no exact match was found and the caller wants an exact match, throw
Int32 numTests = ((BindingFlags.ExactBinding & bindingAttr) != 0) ? 1 : 3;
for (Int32 test = 0; test < numTests; test++) {
CompareParamAndArgTypesFlags flags = CompareParamAndArgTypesFlags.Exact;
// Look for methods whose parameter types exactly match the argument types
if (test == 0)
flags = CompareParamAndArgTypesFlags.Exact;
// Look for methods that can accomodate the parameters passed.
if (test == 1)
flags = CompareParamAndArgTypesFlags.AllowBaseTypes;
// Check whether any conversion could be applied on primitives as well.
// NOTE: We bind to the first matching method; not the best matching method.
// Look for methods that can accomodate the parameters passed.
if (test == 2)
flags = CompareParamAndArgTypesFlags.AllowBaseTypes |
CompareParamAndArgTypesFlags.CoerceValueTypes;
// Assume that no method matches the argument's parameters
MethodBase match = null;
// Check ALL of the methods
foreach (MethodBase m in candidates) {
if (CompareParamAndArgTypes(m.GetParameters(), argTypes, flags)) {
// A matching method was found
// If we found a matching method previously, then we don't know
// how to select one of them.
if (match != null) {
// Note, when doing an exact match this can occur if multiple
// methods differ only by return type
throw new AmbiguousMatchException("Multiple methods match the specified parameter types.");
}
// Save the matching method
match = m;
}
}
// One matching method was found, return it
if (match != null) return match;
}
// No matching method was found, throw
throw new MissingMethodException("Member not found.");
}
// Called to return the parameters of a property
private static ParameterInfo[] GetPropertyParams(PropertyInfo p) {
// If a get accessor method exists, return its parameters
MethodInfo m = p.GetGetMethod();
if (m != null) return m.GetParameters();
// No get accessor method exists, use the set access method
m = p.GetSetMethod();
ParameterInfo[] setParams = m.GetParameters();
// Copy all elements but the last (the property's type) to a new array
ParameterInfo[] paramTypes = new ParameterInfo[setParams.Length - 1];
Array.Copy(setParams, paramTypes, paramTypes.Length);
// Return the copy
return paramTypes;
}
// GetProperty calls this method to select a specific property.
// This code performs uses simple conversion rules to bind.
public override PropertyInfo SelectProperty(
BindingFlags bindingAttr, // Flags to restrict options
PropertyInfo[] properties, // Property subset selected by reflection
Type returnType, // Property's return type
Type[] argTypes, // Set of argument types
ParameterModifier[] modifiers) { // Modifiers (usually ignored)
// This ArrayList contains the set of possible properties
ArrayList candidates = new ArrayList();
// Build the set of candidate properties removing any property that
// doesn't have the specified number of arguments.
// Only consider properties that have the same number of arguments and type
Int32 argCount = (argTypes == null) ? 0 : argTypes.Length;
foreach (PropertyInfo p in properties) {
if (GetPropertyParams(p).Length == argCount)
// Check the property's type
if ((returnType == null) || (returnType == p.PropertyType))
candidates.Add(p);
}
// If no exact match was found and the caller wants an exact match, throw
Int32 numTests = ((BindingFlags.ExactBinding & bindingAttr) != 0) ? 1 : 3;
for (Int32 test = 0; test < numTests; test++) {
CompareParamAndArgTypesFlags flags = CompareParamAndArgTypesFlags.Exact;
// Look for properties whose parameter types exactly match the argument types
if (test == 0)
flags = CompareParamAndArgTypesFlags.Exact;
// Look for properties that can accomodate the parameters passed.
if (test == 1)
flags = CompareParamAndArgTypesFlags.AllowBaseTypes;
// Check whether any conversion could be applied on primitives as well.
// NOTE: We bind to the first matching property; not the best matching property.
// Look for properties that can accomodate the parameters passed.
if (test == 2)
flags = CompareParamAndArgTypesFlags.AllowBaseTypes |
CompareParamAndArgTypesFlags.CoerceValueTypes;
// Assume that no property matches the argument's parameters
PropertyInfo match = null;
// Check ALL of the properties
foreach (PropertyInfo p in candidates) {
if (CompareParamAndArgTypes(GetPropertyParams(p), argTypes, flags)) {
// A matching property was found
// If we found a matching property previously, then we don't know
// how to select one of them.
if (match != null) {
// Note, when doing an exact match this can occur if multiple
// properties differ only by type
throw new AmbiguousMatchException("Multiple properties match the specified parameter types.");
}
// Save the matching property
match = p;
}
}
// One matching property was found, return it
if (match != null) return match;
}
// No matching property was found, throw
throw new MissingMemberException("Member not found.");
}
///////////////////////////////////////////////////////////////////////////////
// This table indicates what conversions this binder allows
static readonly TypeCode[][] AllowedConversions = new TypeCode[19][];
// This static constructor initializes the conversion table
static SimpleBinder() {
// For example, Char can be convert to SByte, Byte, or UInt16
AllowedConversions[(Int32) TypeCode.Char] = new TypeCode[]
{ TypeCode.SByte, TypeCode.Byte, TypeCode.UInt16 };
AllowedConversions[(Int32) TypeCode.Int16] = new TypeCode[]
{ TypeCode.SByte, TypeCode.Byte };
AllowedConversions[(Int32) TypeCode.UInt16] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte };
AllowedConversions[(Int32) TypeCode.Int32] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16 };
AllowedConversions[(Int32) TypeCode.UInt32] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16 };
AllowedConversions[(Int32) TypeCode.Int64] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32 };
AllowedConversions[(Int32) TypeCode.UInt64] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32 };
AllowedConversions[(Int32) TypeCode.Single] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16 };
AllowedConversions[(Int32) TypeCode.Double] = new TypeCode[]
{ TypeCode.Char, TypeCode.SByte, TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Single };
}
// Returns 'true' if the binder can convert from fromType to toType
private static Boolean CanConvertPrimitiveType(Type fromType, Type toType) {
// If the types are the same, of course we can convert
if (fromType == toType) return true;
// Check table to see if fromType can be converted to anything
TypeCode fromTypeCode = Type.GetTypeCode(fromType);
if (AllowedConversions[(Int32) fromTypeCode] == null)
return false;
// Check table to see if conversion from fromType to toType is allowed
TypeCode toTypeCode = Type.GetTypeCode(toType);
if (Array.IndexOf(AllowedConversions[(Int32) toTypeCode], fromTypeCode) != -1)
return true;
// Conversion is not allowed
return false;
}
// Returns new object converted from original type
private static Object DoConvertPrimitiveType(Object value, Type toType) {
// If conversion isn't allowed, throw
if (!CanConvertPrimitiveType(value.GetType(), toType))
throw new InvalidCastException();
// Conversion is allowed, convert and return the new object
return Convert.ChangeType(value, toType);
}
}
//////////////////////////////// End of File //////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -