/// <summary> /// 返回指定类型的对象,其值等效于指定对象。参数提供区域性特定的格式设置信息。 /// 只对允许进行隐式类型转换。 /// </summary> /// <param name="value">要转换的对象。</param> /// <param name="conversionType">要返回的对象的类型。</param> /// <param name="provider">一个提供区域性特定的格式设置信息的对象。</param> /// <returns>一个对象,其类型为 <paramref name="conversionType"/>, /// 并且其值等效于 <paramref name="value"/>。</returns> internal static object ImplicitChangeType(object value, Type conversionType, IFormatProvider provider) { Type nonNullableType; if (BasicChangeType(ref value, conversionType, out nonNullableType)) { return value; } Type type = value.GetType(); // 尝试标准隐式类型转换。 bool success; object result = StandardImplicitChangeType(value, type, nonNullableType, provider, out success); if (success) { return result; } // 对隐式类型转换运算符进行判断。 ConversionMethod method = ConversionCache.GetImplicitConversion(type, conversionType); if (method != null) { value = MethodInfo.GetMethodFromHandle(method.Method).Invoke(null, new object[] { value }); if (value != null) { type = value.GetType(); if (type != nonNullableType) { // 处理用户定义隐式类型转换之后的标准隐式类型转换。 value = StandardImplicitChangeType(value, type, nonNullableType, provider, out success); } } return value; } throw CommonExceptions.ConvertInvalidValue(value, conversionType); }
/// <summary> /// 根据给定的用户定义转换获取最合适的转换。 /// </summary> /// <param name="method">要测试的用户定义转换。</param> /// <param name="exactSource">当前最合适的源类型。</param> /// <param name="exactTarget">当前最合适的目标类型。</param> /// <param name="uniqueMethod">最合适的转换。</param> private static void GetBestConversion(ConversionMethod method, ref Type exactSource, ref Type exactTarget, UniqueValue <ConversionMethod> uniqueMethod) { if (exactSource != method.SourceType) { if (exactSource != null && method.SourceType.IsAssignableFrom(exactSource)) { return; } else { exactSource = method.SourceType; uniqueMethod.Reset(); } } if (exactTarget != method.TargetType) { if (exactTarget != null && exactTarget.IsAssignableFrom(method.TargetType)) { return; } else { exactTarget = method.TargetType; uniqueMethod.Reset(); } } uniqueMethod.Value = method; }
/// <summary> /// 返回从源类型到目标类型的用户定义的显式转换方法。 /// 该转换方法的参数与源类型和目标类型并不一定完全相同,但保证存在标准显式转换。 /// </summary> /// <param name="sourceType">要获取用户定义的转换方法的源类型。</param> /// <param name="targetType">要获取用户定义的转换方法的目标类型。</param> /// <returns>如果存在从源类型到目标类型的用户定义的显式转换方法,则返回该方法; /// 否则返回 <c>null</c>。</returns> public static ConversionMethod GetExplicitConversion(Type sourceType, Type targetType) { Type exactSource = null, exactTarget = null; UniqueValue <ConversionMethod> method = new UniqueValue <ConversionMethod>(); Conversion conv = GetTypeConversions(sourceType.GetNonNullableType()); for (int i = conv.ConvertToIndex; i < conv.Methods.Length; i++) { ConversionMethod m = conv.Methods[i]; if (targetType.IsStandardExplicitFrom(m.TargetType)) { GetBestConversion(m, ref exactSource, ref exactTarget, method); } } conv = GetTypeConversions(targetType.GetNonNullableType()); for (int i = Conversion.ConvertFromIndex; i < conv.ConvertToIndex; i++) { ConversionMethod m = conv.Methods[i]; if (m.SourceType.IsStandardExplicitFrom(sourceType)) { GetBestConversion(m, ref exactSource, ref exactTarget, method); } } if (method.IsUnique) { return(method.Value); } return(null); }
/// <summary> /// 返回指定类型的对象,其值等效于指定对象。参数提供区域性特定的格式设置信息。 /// 支持可空类型、枚举和用户自定义类型转换。 /// </summary> /// <param name="value">要转换的对象。</param> /// <param name="conversionType">要返回的对象的类型。</param> /// <param name="provider">一个提供区域性特定的格式设置信息的对象。</param> /// <returns>一个对象,其类型为 <paramref name="conversionType"/>, /// 并且其值等效于 <paramref name="value"/>。</returns> /// <overloads> /// <summary> /// 返回指定类型的对象,其值等效于指定对象。支持可空类型、枚举和用户自定义类型转换。 /// </summary> /// </overloads> public static object ChangeType(object value, Type conversionType, IFormatProvider provider) { Type nonNullableType; if (BasicChangeType(ref value, conversionType, out nonNullableType)) { return value; } Type type = value.GetType(); // 尝试显示枚举转换。 if (conversionType.IsEnumExplicitFrom(type)) { if (conversionType.IsEnum) { // Enum.ToObject 不支持 char, float, double 和 decimal。 switch (Type.GetTypeCode(type)) { case TypeCode.Char: value = (ushort)(char)value; break; case TypeCode.Single: value = (long)(float)value; break; case TypeCode.Double: value = (long)(double)value; break; case TypeCode.Decimal: value = (long)(decimal)value; break; } return Enum.ToObject(conversionType, value); } return Convert.ChangeType(value, conversionType, provider); } // 尝试标准显式类型转换。 bool success; object result = StandardExplicitChangeType(value, type, nonNullableType, provider, out success); if (success) { return result; } // 对显式类型转换运算符进行判断。 ConversionMethod method = ConversionCache.GetExplicitConversion(type, conversionType); if (method != null) { value = MethodBase.GetMethodFromHandle(method.Method).Invoke(null, new [] { value }); if (value != null) { type = value.GetType(); if (type != nonNullableType) { // 处理用户定义显式类型转换之后的标准显式类型转换。 value = StandardExplicitChangeType(value, type, nonNullableType, provider, out success); } } return value; } // 尝试其他支持的转换。 return Convert.ChangeType(value, conversionType, provider); }
/// <summary> /// 根据给定的用户定义转换获取最合适的转换。 /// </summary> /// <param name="method">要测试的用户定义转换。</param> /// <param name="exactSource">当前最合适的源类型。</param> /// <param name="exactTarget">当前最合适的目标类型。</param> /// <param name="uniqueMethod">最合适的转换。</param> private static void GetBestConversion(ConversionMethod method, ref Type exactSource, ref Type exactTarget, UniqueValue<ConversionMethod> uniqueMethod) { if (exactSource != method.SourceType) { if (exactSource != null && method.SourceType.IsAssignableFrom(exactSource)) { return; } else { exactSource = method.SourceType; uniqueMethod.Reset(); } } if (exactTarget != method.TargetType) { if (exactTarget != null && exactTarget.IsAssignableFrom(method.TargetType)) { return; } else { exactTarget = method.TargetType; uniqueMethod.Reset(); } } uniqueMethod.Value = method; }
/// <summary> /// 返回指定类型中用户定义的转换方法。 /// </summary> /// <param name="type">要获取类型转换方法的类型。</param> /// <returns>指定类型中用户定义的转换方法。</returns> private static Conversion GetTypeConversions(Type type) { TypeCode typeCode = Type.GetTypeCode(type); if (typeCode != TypeCode.Object && typeCode != TypeCode.Decimal) { // 其余内置类型都不包含类型转换运算符。 return(Conversion.Empty); } return(Conversions.GetOrAdd(type, t => { Conversion conv = new Conversion(); List <ConversionMethod> cList = new List <ConversionMethod>(); MethodInfo[] methods = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); for (int i = 0; i < methods.Length; i++) { MethodInfo m = methods[i]; bool opImplicit = m.Name.Equals(ImplicitConversionName, StringComparison.Ordinal); // 如果 opImplicit 已经为 true,则不需要再次进行方法名称的比较。 bool opExplicit = opImplicit ? false : m.Name.Equals(ExplicitConviersionName, StringComparison.Ordinal); if (opImplicit || opExplicit) { if (m.ReturnType == type) { // 转换自其它类型。 int index = conv.ImplicitConvertFromIndex; if (opExplicit) { index = Conversion.ConvertFromIndex; conv.ImplicitConvertFromIndex++; } conv.ConvertToIndex++; conv.ImplicitConvertToIndex++; cList.Insert(index, new ConversionMethod(m.GetParameters()[0].ParameterType, t, m)); } else { // 转换到其它类型。 int index = conv.ImplicitConvertToIndex; if (opExplicit) { index = conv.ConvertToIndex; conv.ImplicitConvertToIndex++; } cList.Insert(index, new ConversionMethod(t, m.ReturnType, m)); } } } // 如果子类的类型转换运算符与基类完全相同,则为 true;否则为 false。 bool sameWithBase = (cList.Count == 0); // 基类转换为其它类型的运算符是可以由子类继承的。 if (type.IsClass) { Conversion baseConv = GetTypeConversions(type.BaseType); for (int i = baseConv.ConvertToIndex; i < baseConv.Methods.Length; i++) { ConversionMethod m = baseConv.Methods[i]; bool contains = false; for (int j = conv.ConvertToIndex; j < cList.Count; j++) { if (cList[j].TargetType == m.TargetType) { sameWithBase = false; contains = true; break; } } if (!contains) { if (i >= baseConv.ImplicitConvertToIndex) { cList.Insert(conv.ImplicitConvertToIndex, m); } else { cList.Insert(conv.ConvertToIndex, m); conv.ImplicitConvertToIndex++; } } } if (sameWithBase) { // 这时候可以略微节约内存。 return baseConv; } } if (sameWithBase) { // 这时候可以略微节约内存。 return Conversion.Empty; } conv.Methods = cList.ToArray(); return conv; })); }