/// <summary> /// 基于指定的判据,从给定的字段集中选择一个字段。 /// </summary> /// <param name="bindingAttr"><see cref="BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选字段集。<see cref="PowerBinder"/> 的实现会更改此数组的顺序。</param> /// <param name="value">用于定位匹配字段的字段值。</param> /// <param name="culture">一个 <see cref="CultureInfo"/> 实例, /// 用于在强制类型的联编程序实现中控制数据类型强制。</param> /// <returns>匹配的字段。</returns> /// <exception cref="ArgumentNullException"><paramref name="match"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentException"><paramref name="match"/> 为空数组。</exception> /// <exception cref="ArgumentException"><paramref name="match"/> 中包含为 <c>null</c> 的元素。</exception> /// <exception cref="AmbiguousMatchException"><paramref name="match"/> 包含多个与 <paramref name="value"/> /// 匹配程度相同的字段。</exception> /// <exception cref="MissingFieldException"><paramref name="bindingAttr"/> 包含 /// <see cref="BindingFlags.SetField"/>,且 <paramref name="match"/> 不包含任何可接受 <paramref name="value"/> /// 的字段。</exception> public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, [CanBeNull] object value, CultureInfo culture) { CommonExceptions.CheckCollectionItemNull(match, "match"); Contract.EndContractBlock(); int length = 0; if (bindingAttr.HasFlag(BindingFlags.SetField)) { // 在设置 SetField 标志时,根据 value 的类型进行选择。 Type valueType = value == null ? null : value.GetType(); for (int i = 0; i < match.Length; i++) { if (CanChangeType(valueType, match[i].FieldType)) { match[length++] = match[i]; } } if (length == 0) { throw CommonExceptions.MissingField(); } if (length > 1 && valueType != null) { // 多个可匹配字段,尝试寻找类型最匹配的字段。 length = FilterMember(match, length, (firstField, secondField) => CompareType(firstField.FieldType, secondField.FieldType, valueType)); } } else { length = match.Length; } FieldInfo best = GetDeepestMember(match, length); if (best == null) { throw CommonExceptions.AmbiguousMatchField(); } return(best); }
/// <summary> /// 基于指定的判据,从给定的字段集中选择一个字段。 /// </summary> /// <param name="bindingAttr"><see cref="System.Reflection.BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选字段集。</param> /// <param name="value">用于定位匹配字段的字段值。</param> /// <param name="culture">一个 <see cref="System.Globalization.CultureInfo"/> 实例, /// 用于在强制类型的联编程序实现中控制数据类型强制。</param> /// <returns>匹配的字段。</returns> public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture) { int idx = 0; Type valueType = null; if (value != null) { valueType = value.GetType(); } bool setField = (bindingAttr & BindingFlags.SetField) != 0; if (setField) { // 在设置 SetField 标志时,根据 value 的类型进行选择。 for (int i = 0; i < match.Length; i++) { if (CanChangeType(match[i].FieldType, valueType)) { match[idx++] = match[i]; } } if (idx == 0) { // 没有可匹配的字段。 return(null); } else if (idx > 1 && valueType != null) { // 多个可匹配字段,尝试寻找类型匹配的最好的字段。 int len = idx; idx = 1; for (int i = 1; i < len; i++) { // 尝试进一步匹配字段类型。 int cmp = FindMostSpecificType(match[0].FieldType, match[i].FieldType, valueType); if (cmp == 0) { match[idx++] = match[i]; } else if (cmp == 2) { match[0] = match[i]; idx = 1; } } } } else { idx = match.Length; } // 多个可匹配字段,寻找定义深度最深的字段。 int min = 0; bool ambig = false; for (int i = 1; i < idx; i++) { // 比较定义的层级深度。 int cmp = CompareHierarchyDepth(match[min], match[i]); if (cmp == 0) { ambig = true; } else if (cmp == 2) { min = i; ambig = false; } } if (ambig) { throw CommonExceptions.AmbiguousMatchField(); } return(match[min]); }