/// <summary> /// 将数组使用指定的值填充。 /// </summary> /// <typeparam name="T">数组中元素的类型。</typeparam> /// <param name="array">要填充的数组。</param> /// <param name="value">要填充数组的值。</param> /// <returns>填充完毕的数组。</returns> /// <exception cref="System.ArgumentNullException"><paramref name="array"/> 为 <c>null</c>。</exception> public static T[] Fill <T>(this T[] array, T value) { CommonExceptions.CheckArgumentNull(array, nameof(array)); Contract.Ensures(Contract.Result <T[]>() != null); return(FillInternal(array, value, 0, array.Length)); }
/// <summary> /// 添加将对象从 <typeparamref name="TInput"/> 类型转换为 <typeparamref name="TOutput"/> 类型的转换器。 /// </summary> /// <typeparam name="TInput">输入对象的类型。</typeparam> /// <typeparam name="TOutput">输出对象的类型。</typeparam> /// <param name="converter">将对象从 <typeparamref name="TInput"/> 类型转换为 /// <typeparamref name="TOutput"/> 类型的转换器。</param> /// <exception cref="ArgumentNullException"><paramref name="converter"/> 为 <c>null</c>。</exception> /// <remarks><paramref name="converter"/> 不会覆盖预定义的隐式、显式类型转换和用户自定义的类型转换。 /// 对于相同输入/输出类型的 <paramref name="converter"/>,后设置的会覆盖先设置的,以及任何 /// <see cref="IConverterProvider"/> 提供的类型转换方法。</remarks> public static void AddConverter <TInput, TOutput>(Converter <TInput, TOutput> converter) { CommonExceptions.CheckArgumentNull(converter, nameof(converter)); Contract.EndContractBlock(); ConversionFactory.AddConverterProvider(new ConverterProvider(converter, typeof(TInput), typeof(TOutput))); }
/// <summary> /// 将数组使用指定的值填充。 /// </summary> /// <param name="array">要填充的数组。</param> /// <param name="value">要填充数组的值。</param> /// <returns>填充完毕的数组。</returns> /// <exception cref="System.ArgumentNullException"><paramref name="array"/> 为 <c>null</c>。</exception> /// <overloads> /// <summary> /// 将数组使用指定的值填充。 /// </summary> /// </overloads> public static Array Fill(this Array array, object value) { CommonExceptions.CheckArgumentNull(array, nameof(array)); Contract.Ensures(Contract.Result <Array>() != null); return(FillInternal(array, value, 0, array.Length)); }
/// <summary> /// 使用被包装的进度更新提供程序初始化 <see cref="RemoteProgress{T}"/> 类的新实例。 /// </summary> /// <param name="progress">被包装的进度更新提供程序。</param> public RemoteProgress(IProgress <T> progress) { CommonExceptions.CheckArgumentNull(progress, nameof(progress)); Contract.EndContractBlock(); this.progress = progress; }
/// <summary> /// 使用指定的标识符初始化 <see cref="ProcessorAttribute"/> 类的新实例。 /// </summary> /// <param name="id">处理器的标识符。</param> /// <exception cref="ArgumentException"><paramref name="id"/> 为 <c>null</c> 或空字符串。</exception> public ProcessorAttribute(string id) { CommonExceptions.CheckStringEmpty(id, "id"); Contract.EndContractBlock(); this.id = id; }
/// <summary> /// 基于提供的参数,从给定的方法集中选择要调用的方法。 /// </summary> /// <param name="bindingAttr"><see cref="System.Reflection.BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选方法集。</param> /// <param name="args">传入的参数。</param> /// <param name="modifiers">使绑定能够处理在其中修改了类型的参数签名的参数修饰符数组。</param> /// <param name="culture">一个 <see cref="System.Globalization.CultureInfo"/> 实例, /// 用于在强制类型的联编程序实现中控制数据类型强制。</param> /// <param name="names">参数名(如果匹配时要考虑参数名)或 <c>null</c>(如果要将变量视为纯位置)。</param> /// <param name="state">方法返回之后,<paramref name="state"/> 包含一个联编程序提供的对象, /// 用于跟踪参数的重新排序。</param> /// <returns>匹配的方法。</returns> public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state) { if (match == null) { throw CommonExceptions.ArgumentNull("match"); } if (match.Length == 0) { throw CommonExceptions.ArrayEmpty("match"); } // 检查参数名称数组,不能出现名称相同的两个参数。 if (names != null) { CheckNames(names); } // 构造方法信息数组。 MatchInfo[] infos = new MatchInfo[match.Length]; MatchInfo info = null; int idx = 0; for (int i = 0; i < match.Length; i++) { if (match[i] != null) { info = new MatchInfo(match[i]); int len = info.Parameters.Length > args.Length ? info.Parameters.Length : args.Length; if (names == null) { info.ParamOrder = info.ParamOrderRev = MethodExt.GetParamOrder(len); } else { info.ParamOrder = new int[len]; // 根据 names 创建参数顺序。 if (!CreateParamOrder(info.ParamOrder, info.Parameters, names)) { continue; } } infos[idx++] = info; } } if (idx == 0) { // 没有可匹配的方法。 state = null; return(null); } Type[] types = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { // types[i] 为 null 表示可以匹配任何引用类型。 if (args[i] != null) { types[i] = args[i].GetType(); } } info = SelectMethod(bindingAttr, infos, idx, types); if (info == null) { // 没有可匹配的方法。 state = null; return(null); } UpdateArgs(info, ref args, names != null, out state); return(info.Method); }
/// <summary> /// 将一个或多个枚举常数的名称、描述或数字值的字符串表示转换成等效的枚举对象。 /// 一个参数指定该操作是否区分大小写。 /// </summary> /// <param name="enumType">枚举类型。</param> /// <param name="value">包含要转换的值或名称的字符串。</param> /// <param name="ignoreCase">若要忽略大小写则为 <c>true</c>; /// 否则为 <c>false</c>。</param> /// <returns><paramref name="enumType"/> 类型的对象,其值由 <paramref name="value"/> 表示。</returns> /// <exception cref="System.ArgumentNullException"> /// <paramref name="value"/> 为 <c>null</c>。</exception> /// <exception cref="System.ArgumentException"> /// <paramref name="enumType"/> 不是 <see cref="System.Enum"/>。</exception> /// <exception cref="System.ArgumentException"> /// <paramref name="value"/> 是空字符串 ("") 或只包含空白。</exception> /// <exception cref="System.ArgumentException"> /// <paramref name="value"/> 是一个名称,但不是为该枚举定义的命名常量之一。</exception> /// <exception cref="System.OverflowException"> /// <paramref name="value"/> 超出 <paramref name="enumType"/> /// 基础类型的范围。</exception> public static object ParseEx(Type enumType, string value, bool ignoreCase) { CommonExceptions.CheckArgumentNull(enumType, "enumType"); CommonExceptions.CheckArgumentNull(value, "value"); if (!enumType.IsEnum) { throw CommonExceptions.MustBeEnum("enumType", enumType); } value = value.Trim(); if (value.Length == 0) { throw CommonExceptions.MustContainEnumInfo("value"); } // 尝试对数字进行解析,这样可避免之后的字符串比较。 ulong tmpValue; if (ParseString(value, out tmpValue)) { return(Enum.ToObject(enumType, tmpValue)); } // 尝试对描述信息进行解析。 EnumCache cache = GetEnumCache(enumType); StringComparison comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; ulong valueUL = 0; int start = 0; do { // 去除前导空白。 while (char.IsWhiteSpace(value, start)) { start++; } int idx = value.IndexOf(',', start); if (idx < 0) { idx = value.Length; } int nIdx = idx - 1; // 去除后面的空白。 while (char.IsWhiteSpace(value, nIdx)) { nIdx--; } if (nIdx >= start) { string str = value.Substring(start, nIdx - start + 1); int j = 0; // 比较常数值的名称和描述信息,先比较名称,后比较描述信息。 for (; j < cache.Names.Length; j++) { if (string.Equals(str, cache.Names[j], comparison)) { // 与常数值匹配。 valueUL |= cache.Values[j]; break; } } if (j == cache.Names.Length && cache.HasDescription) { // 比较描述信息。 for (j = 0; j < cache.Descriptions.Length; j++) { if (string.Equals(str, cache.Descriptions[j], comparison)) { // 与描述信息匹配。 valueUL |= cache.Values[j]; break; } } } // 未识别的枚举值。 if (j == cache.Descriptions.Length) { // 尝试识别为数字。 if (ParseString(str, out tmpValue)) { valueUL |= tmpValue; } else { // 不能识别为数字。 throw CommonExceptions.EnumValueNotFound(enumType, str); } } } start = idx + 1; } while (start < value.Length); return(Enum.ToObject(enumType, valueUL)); }
/// <summary> /// 使用指定的实例属性,初始化 <see cref="MemberAccessor{T}"/> 类的新实例, /// 表示指定的实例属性。 /// </summary> /// <param name="property">要访问的实例属性。</param> /// <param name="nonPublic">指示是否应访问非公共实例属性。 /// 如果要访问非公共实例属性,则为 <c>true</c>;否则为 <c>false</c>。</param> public MemberAccessor(PropertyInfo property, bool nonPublic) { CommonExceptions.CheckArgumentNull(property, "property"); this.name = property.Name; Init(property, nonPublic); }
/// <summary> /// 使用指定的字段,初始化 <see cref="MemberAccessor{T}"/> 类的新实例, /// 表示指定的字段。 /// </summary> /// <param name="field">要访问的字段。</param> public MemberAccessor(FieldInfo field) { CommonExceptions.CheckArgumentNull(field, "field"); this.name = field.Name; Init(field); }
/// <summary> /// 将一个或多个枚举常数的名称或数字值的字符串表示转换成等效的枚举对象。 /// 一个参数指定该操作是否区分大小写。 /// </summary> /// <typeparam name="TEnum">要获取枚举对象的枚举类型。</typeparam> /// <param name="value">包含要转换的值或名称的字符串。</param> /// <param name="ignoreCase"><c>true</c> 为忽略大小写;<c>false</c> 为考虑大小写。</param> /// <returns><typeparamref name="TEnum"/> 类型的对象,其值由 <paramref name="value"/> 表示。</returns> /// <exception cref="ArgumentNullException"><paramref name="value"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentException"><typeparamref name="TEnum"/> 不是 <see cref="System.Enum"/>。</exception> /// <exception cref="ArgumentException"><paramref name="value"/> 是空字符串 ("") 或只包含空白。</exception> /// <exception cref="ArgumentException"><paramref name="value"/> 是一个名称,但不是为该枚举定义的命名常量之一。 /// </exception> /// <exception cref="OverflowException"><paramref name="value"/> 超出 <typeparamref name="TEnum"/> /// 基础类型的范围。</exception> public static TEnum Parse <TEnum>(string value, bool ignoreCase) { CommonExceptions.CheckArgumentNull(value, "value"); Contract.EndContractBlock(); return((TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase)); }
/// <summary> /// 随机打乱转序列中元素的顺序。 /// </summary> /// <typeparam name="TSource"><paramref name="source"/> 中的元素的类型。 /// </typeparam> /// <param name="source">要随机打乱顺序的值序列。</param> /// <returns>一个序列,其元素以随机顺序对应于输入序列的元素。</returns> public static IEnumerable <TSource> RandomOrder <TSource>( this IEnumerable <TSource> source) { CommonExceptions.CheckArgumentNull(source, "source"); return(source.ToArray().Random()); }
/// <summary> /// 检索指定枚举类型中常数描述和值的集合。如果不存在描述,则使用其名称。 /// </summary> /// <typeparam name="TEnum">枚举类型。</typeparam> /// <returns>一个 <see cref="TextValuePairCollection"/> 实例,其中包含 /// <typeparamref name="TEnum"/> 中实例的名称和值。该集合的元素按枚举的二进制值排序。</returns> /// <exception cref="ArgumentException"><typeparamref name="TEnum"/> 不是 <see cref="Enum"/>。</exception> public static TextValuePairCollection <TEnum> GetDescValues <TEnum>() { Contract.Ensures(Contract.Result <TextValuePairCollection <TEnum> >() != null); CommonExceptions.CheckEnumType(typeof(TEnum)); return(GetTextValues <TEnum>(true)); }
/// <summary> /// 返回与指定标识符相关的处理器方法集合。 /// </summary> /// <typeparam name="TDelegate">使用基类型调用方法的委托。</typeparam> /// <param name="type">在其中查找静态或实例方法的类型。</param> /// <param name="id">方法切换器的标识符。</param> /// <param name="index">方法的关键参数索引。</param> /// <param name="queryStatic">是否请求的是静态方法。</param> /// <returns>与指定标识符相关的处理器方法集合。</returns> private static Dictionary <Type, Delegate> GetMethods <TDelegate>(Type type, string id, int index, bool queryStatic) { Type dlgType = typeof(TDelegate); Tuple <bool, Type, Dictionary <Type, Delegate> > data; string key = string.Concat(type.FullName, "_", id); if (!methodDict.TryGetValue(key, out data)) { MethodInfo[] methods = type.GetMethods(MethodFlags); List <MethodInfo> list = new List <MethodInfo>(); for (int i = 0; i < methods.Length; i++) { if (methods[i].GetCustomAttributes(typeof(ProcessorAttribute), true) .Cast <ProcessorAttribute>().Any(s => s.Id == id)) { list.Add(methods[i]); } } int cnt = list.Count; if (cnt == 0) { throw CommonExceptions.ProcessorNotFound("type", type, id); } bool isStatic = list[0].IsStatic; for (int i = 1; i < cnt; i++) { if (list[i].IsStatic != isStatic) { throw CommonExceptions.ProcessorMixed("type", type, id); } } Dictionary <Type, Delegate> dict = new Dictionary <Type, Delegate>(); Type newDlgType = dlgType; if (!isStatic) { newDlgType = GetInstanceDlgType(newDlgType); } for (int i = 0; i < cnt; i++) { Type keyType = list[i].GetParameters()[index].ParameterType; Delegate dlg = DelegateBuilder.CreateDelegate(newDlgType, list[i], false); if (dlg == null) { throw CommonExceptions.DelegateCompatible(list[i].ToString(), dlgType); } dict.Add(keyType, dlg); } data = new Tuple <bool, Type, Dictionary <Type, Delegate> >(isStatic, dlgType, dict); methodDict.Add(key, data); } if (data.Item1 != queryStatic) { throw CommonExceptions.ProcessorMismatch("type", type, id); } if (data.Item2 != dlgType) { // 检查委托参数。 ParameterInfo[] paramInfos = data.Item2.GetMethod("Invoke").GetParameters(); ParameterInfo[] dlgParamInfos = dlgType.GetMethod("Invoke").GetParameters(); if (paramInfos.Length != dlgParamInfos.Length) { throw CommonExceptions.DelegateCompatible("TDelegate", dlgType); } for (int i = 0; i < paramInfos.Length; i++) { if (paramInfos[i].ParameterType != dlgParamInfos[i].ParameterType) { throw CommonExceptions.DelegateCompatible("TDelegate", dlgType); } } } return(data.Item3); }
/// <summary> /// 基于指定的判据,从给定的属性集中选择一个属性。 /// </summary> /// <param name="bindingAttr"><see cref="System.Reflection.BindingFlags"/> 值的按位组合。</param> /// <param name="match">用于匹配的候选属性集。</param> /// <param name="returnType">匹配属性必须具有的返回值。</param> /// <param name="indexes">所搜索的属性的索引类型。</param> /// <param name="modifiers">使绑定能够处理在其中修改了类型的参数签名的参数修饰符数组。</param> /// <returns>如果找到,则为匹配的属性;否则为 <c>null</c>。</returns> public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers) { CommonExceptions.CheckArgumentNull(match, "match"); if (match.Length == 0) { return(null); } int idxLen = indexes == null ? 0 : indexes.Length; // 构造属性信息数组。 MatchInfo[] infos = new MatchInfo[match.Length]; int idx = 0; for (int i = 0; i < match.Length; i++) { if (match[i] != null) { ParameterInfo[] parameters = match[i].GetIndexParameters(); // 匹配属性类型与索引参数。 if (parameters.Length == idxLen && CheckParameters(infos[i], indexes, idxLen) && CanChangeType(match[i].PropertyType, returnType)) { infos[idx] = new MatchInfo(parameters, MethodExt.GetParamOrder(idxLen)); match[idx] = match[i]; idx++; } } } if (idx == 0) { return(null); } if (idx == 1) { return(match[0]); } // 多个可匹配属性,寻找匹配的最好的属性。 int min = 0; bool ambig = false; for (int i = 1; i < idx; i++) { // 先比较属性类型。 int cmp = FindMostSpecificType(match[min].PropertyType, match[i].PropertyType, returnType); if (cmp == 0 && indexes != null) { // 再比较属性参数。 cmp = FindMostSpecific(infos[min], infos[i], indexes); } if (cmp == 0) { // 最后比较定义的层级深度。 cmp = CompareHierarchyDepth(match[min], match[i]); if (cmp == 0) { ambig = true; } } if (cmp == 2) { ambig = false; min = i; } } if (ambig) { throw CommonExceptions.AmbiguousMatchProperty(); } return(match[min]); }
/// <summary> /// 用随机数填充指定字节数组的元素。 /// </summary> /// <param name="buffer">包含随机数的字节数组。</param> /// <exception cref="ArgumentNullException"><paramref name="buffer"/> 为 <c>null</c>。</exception> public static void NextBytes(byte[] buffer) { CommonExceptions.CheckArgumentNull(buffer, nameof(buffer)); Contract.EndContractBlock(); Random.NextBytes(buffer); }
/// <summary> /// 创建表示指定的静态或实例方法的的委托。如果是实例方法,需要将实例对象作为第一个参数; /// </summary> /// <param name="method">描述委托要表示的静态或实例方法的 <see cref="MethodInfo"/>。</param> /// <returns>表示指定的静态或实例方法的委托。</returns> /// <remarks>如果是静态方法,则第一个参数无效。对于可变参数方法,只支持固定参数。</remarks> /// <exception cref="ArgumentNullException"><paramref name="method"/> 为 <c>null</c>。</exception> /// <exception cref="ArgumentException"><paramref name="method"/> 是开放构造方法。</exception> /// <exception cref="MethodAccessException">调用方无权访问 <paramref name="method"/>。</exception> public static MethodInvoker CreateDelegate(this MethodInfo method) { CommonExceptions.CheckArgumentNull(method, nameof(method)); Contract.Ensures(Contract.Result <MethodInvoker>() != null); if (method.ContainsGenericParameters) { // 不能对开放构造方法执行绑定。 throw CommonExceptions.BindOpenConstructedMethod(nameof(method)); } var dlgMethod = new DynamicMethod("MethodInvoker", typeof(object), new[] { typeof(object), typeof(object[]) }, method.Module, true); var il = dlgMethod.GetILGenerator(); Contract.Assume(il != null); var parameters = method.GetParametersNoCopy(); var len = parameters.Length; // 参数数量检测。 if (len > 0) { il.EmitCheckArgumentNull(1, "parameters"); il.Emit(OpCodes.Ldarg_1); il.EmitCheckTargetParameterCount(parameters.Length); } // 加载实例对象。 if (!method.IsStatic) { il.EmitLoadInstance(method, typeof(object), true); } var optimizeTailcall = true; // 加载方法参数。 for (var i = 0; i < len; i++) { il.Emit(OpCodes.Ldarg_1); il.EmitInt(i); var paramType = parameters[i].ParameterType; if (paramType.IsByRef) { paramType = paramType.GetElementType(); var converter = il.GetConversion(typeof(object), paramType, ConversionType.Explicit); Console.WriteLine(converter); if (converter.NeedEmit) { il.Emit(OpCodes.Ldelem_Ref); converter.Emit(true); var local = il.DeclareLocal(paramType); il.Emit(OpCodes.Stloc, local); il.Emit(OpCodes.Ldloca, local); optimizeTailcall = false; } else { il.Emit(OpCodes.Ldelema, paramType); } } else { il.Emit(OpCodes.Ldelem_Ref); il.EmitConversion(typeof(object), paramType, true, ConversionType.Explicit); } } // 调用函数。 il.EmitInvokeMethod(method, null, typeof(object), optimizeTailcall); return((MethodInvoker)dlgMethod.CreateDelegate(typeof(MethodInvoker))); }
/// <summary> /// 返回不能满足当前条件的条件。 /// </summary> /// <typeparam name="T">要比较的对象的类型。</typeparam> /// <param name="predicate">当前条件。</param> /// <returns>不能满足当前条件的条件。</returns> /// <exception cref="ArgumentNullException"><paramref name="predicate"/> 为 <c>null</c>。</exception> public static Predicate <T> Not <T>(this Predicate <T> predicate) { CommonExceptions.CheckArgumentNull(predicate, "predicate"); Contract.Ensures(Contract.Result <Predicate <T> >() != null); return(obj => !predicate(obj)); }
/// <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]); }