/// <summary> /// 写入类型转换的 IL 指令。 /// </summary> /// <param name="generator">IL 的指令生成器。</param> /// <param name="inputType">要转换的对象的类型。</param> /// <param name="outputType">要将输入对象转换到的类型。</param> /// <param name="isChecked">是否执行溢出检查。</param> public override void Emit(ILGenerator generator, Type inputType, Type outputType, bool isChecked) { Contract.Assume(inputType.IsNullable()); Type inputUnderlyingType = Nullable.GetUnderlyingType(inputType); generator.EmitCall(inputType.GetMethod("get_Value")); if (inputUnderlyingType != outputType) { Conversion conversion = ConversionFactory.GetConversion(inputUnderlyingType, outputType); Contract.Assume(conversion != null); conversion.Emit(generator, inputUnderlyingType, outputType, isChecked); } }
/// <summary> /// 写入类型转换的 IL 指令。 /// </summary> /// <param name="generator">IL 的指令生成器。</param> /// <param name="inputType">要转换的对象的类型。</param> /// <param name="outputType">要将输入对象转换到的类型。</param> /// <param name="isChecked">是否执行溢出检查。</param> public override void Emit(ILGenerator generator, Type inputType, Type outputType, bool isChecked) { Type methodType = method.GetParametersNoCopy()[0].ParameterType; Conversion conv = ConversionFactory.GetPreDefinedConversion(inputType, methodType); conv.Emit(generator, inputType, methodType, isChecked); generator.Emit(OpCodes.Call, method); methodType = method.ReturnType; conv = ConversionFactory.GetPreDefinedConversion(methodType, outputType); if (conv is FromNullableConversion) { generator.EmitGetAddress(methodType); } conv.Emit(generator, methodType, outputType, isChecked); }
/// <summary> /// 写入类型转换的 IL 指令。 /// </summary> /// <param name="generator">IL 的指令生成器。</param> /// <param name="inputType">要被转换的类型。</param> /// <param name="outputType">要转换到的类型。</param> /// <param name="isChecked">是否执行溢出检查。</param> public override void Emit(ILGenerator generator, Type inputType, Type outputType, bool isChecked) { Contract.Assume(inputType.IsNullable()); Type inputUnderlyingType = Nullable.GetUnderlyingType(inputType); Type outputUnderlyingType = Nullable.GetUnderlyingType(outputType); // 定义变量和标签 LocalBuilder inputLocal = generator.GetLocal(inputType); Label trueCase = generator.DefineLabel(); Label endConvert = generator.DefineLabel(); // inputLocal = value; generator.Emit(OpCodes.Stloc, inputLocal); // if (input.HasValue) generator.Emit(OpCodes.Ldloca, inputLocal); MethodInfo hasValue = inputType.GetMethod("get_HasValue"); generator.Emit(OpCodes.Call, hasValue); generator.Emit(OpCodes.Brtrue, trueCase); // return null if (outputUnderlyingType != null) { // Nullable<T>。 generator.EmitDefault(outputType); } else { // 引用类型。 generator.Emit(OpCodes.Ldnull); } generator.Emit(OpCodes.Br, endConvert); // else generator.MarkLabel(trueCase); // (outputType)input.GetValueOrDefault(); generator.Emit(OpCodes.Ldloca, inputLocal); generator.FreeLocal(inputLocal); MethodInfo getValueOrDefault = inputType.GetMethod("GetValueOrDefault", Type.EmptyTypes); generator.Emit(OpCodes.Call, getValueOrDefault); ConversionFactory.GetConversion(inputUnderlyingType, outputUnderlyingType ?? outputType) .Emit(generator, inputUnderlyingType, outputUnderlyingType ?? outputType, isChecked); if (outputUnderlyingType != null) { ConstructorInfo ctor = outputType.GetConstructor(new[] { outputUnderlyingType }); Contract.Assume(ctor != null); generator.Emit(OpCodes.Newobj, ctor); } generator.MarkLabel(endConvert); }
/// <summary> /// 写入类型转换的 IL 指令。 /// </summary> /// <param name="generator">IL 的指令生成器。</param> /// <param name="inputType">要转换的对象的类型。</param> /// <param name="outputType">要将输入对象转换到的类型。</param> /// <param name="isChecked">是否执行溢出检查。</param> public override void Emit(ILGenerator generator, Type inputType, Type outputType, bool isChecked) { Contract.Assume(outputType.IsNullable()); var outputUnderlyingType = Nullable.GetUnderlyingType(outputType); if (inputType != outputUnderlyingType) { var conversion = ConversionFactory.GetConversion(inputType, outputUnderlyingType); Contract.Assume(conversion != null); conversion.Emit(generator, inputType, outputUnderlyingType, isChecked); } var ctor = outputType.GetConstructor(new[] { outputUnderlyingType }); Contract.Assume(ctor != null); generator.Emit(OpCodes.Newobj, ctor); }
/// <summary> /// 更新最优的输入/输出类型。 /// </summary> /// <param name="methodType">类型转换方法的输入/输出类型。</param> /// <param name="relation">实际输入类型与方法输入/输出类型间的关系。</param> /// <param name="relationJudge">方法输入/输出类型和最优类型间的关系判定。</param> /// <param name="bestType">当前的最优类型。</param> /// <param name="bestRelation">当前最优类型与实际输入/输出类型间的关系。</param> private void UpdateBestType(Type methodType, TypeRelation relation, bool relationJudge, ref Type bestType, ref TypeRelation bestRelation) { // 当前选择更差。 if (relation > bestRelation) { return; } // 当前选择更优,或者当前选择与最佳选择相同,但最佳选择没有类型填充。 if (relation < bestRelation || bestType == null) { bestType = methodType; bestRelation = relation; bestMethod.Reset(); return; } ConversionType ctype = ConversionFactory.GetStandardConversion(methodType, bestType); if (ctype == ConversionType.None) { // 找不到类型转换关系,令最佳选择前进至下一级别,并清除类型填充。 bestType = null; bestRelation--; bestMethod.Reset(); return; } if (ctype.IsImplicit() == relationJudge) { // 当前选择被最优选择包含。 if (bestRelation == TypeRelation.Second) { bestType = methodType; bestMethod.Reset(); } } else if (bestRelation == TypeRelation.Thirt) { // 当前选择包含最优选择。 bestType = methodType; bestMethod.Reset(); } }
/// <summary> /// 查找合适的用户自定义类型转换方法。 /// </summary> /// <returns>合适的用户自定义类型转换方法,如果不存在则为 <c>null</c>。</returns> public MethodInfo FindConversion() { UserConversions convs = GetUserConversions(inputType); if (convs != null) { Contract.Assume(convs.ConvertToIndex >= 0); for (int i = convs.ConvertToIndex; i < convs.Methods.Length; i++) { UserConversionMethod method = convs.Methods[i]; ConversionType ctype = ConversionFactory.GetStandardConversion(outputType, method.OutputType); if (ctype == ConversionType.None) { continue; } TypeRelation inputRelation = (method.InputType == inputType) ? TypeRelation.Best : TypeRelation.Second; TypeRelation outputRelation = TypeRelation.Best; if (ctype >= ConversionType.ExplicitNumeric) { outputRelation = TypeRelation.Second; } else if (ctype > ConversionType.Identity) { outputRelation = TypeRelation.Thirt; } GetBestConversion(method, inputRelation, outputRelation); } } convs = GetUserConversions(outputType); if (convs != null) { for (int i = 0; i < convs.ConvertToIndex; i++) { UserConversionMethod method = convs.Methods[i]; ConversionType ctype = ConversionFactory.GetStandardConversion(method.InputType, inputType); if (ctype == ConversionType.None) { continue; } TypeRelation outputRelation = (method.OutputType == outputType) ? TypeRelation.Best : TypeRelation.Second; TypeRelation inputRelation = TypeRelation.Best; if (ctype >= ConversionType.ExplicitNumeric) { inputRelation = TypeRelation.Second; } else if (ctype > ConversionType.Identity) { inputRelation = TypeRelation.Thirt; } GetBestConversion(method, inputRelation, outputRelation); } } if (bestMethod.IsUnique) { return(bestMethod.Value.Method); } if (bestMethod.IsAmbig) { throw CommonExceptions.AmbiguousUserDefinedConverter(inputType, outputType); } return(null); }