{// no IL level conversions to/from decimal; I guess we could use the static operators, but
// this feels an edge-case
handled=false;
}
else
{
caseTypeCode.Byte:
opCode=OpCodes.Conv_Ovf_I1_Un;break;
caseTypeCode.SByte:
opCode=OpCodes.Conv_Ovf_I1;break;
caseTypeCode.UInt16:
opCode=OpCodes.Conv_Ovf_I2_Un;break;
caseTypeCode.Int16:
opCode=OpCodes.Conv_Ovf_I2;break;
caseTypeCode.UInt32:
opCode=OpCodes.Conv_Ovf_I4_Un;break;
caseTypeCode.Boolean:// boolean is basically an int, at least at this level
caseTypeCode.Int32:
opCode=OpCodes.Conv_Ovf_I4;break;
caseTypeCode.UInt64:
opCode=OpCodes.Conv_Ovf_I8_Un;break;
caseTypeCode.Int64:
opCode=OpCodes.Conv_Ovf_I8;break;
caseTypeCode.Single:
opCode=OpCodes.Conv_R4;break;
caseTypeCode.Double:
opCode=OpCodes.Conv_R8;break;
default:
handled=false;
break;
switch(unboxTypeCode)
{
caseTypeCode.Byte:
opCode=OpCodes.Conv_Ovf_I1_Un;break;
caseTypeCode.SByte:
opCode=OpCodes.Conv_Ovf_I1;break;
caseTypeCode.UInt16:
opCode=OpCodes.Conv_Ovf_I2_Un;break;
caseTypeCode.Int16:
opCode=OpCodes.Conv_Ovf_I2;break;
caseTypeCode.UInt32:
opCode=OpCodes.Conv_Ovf_I4_Un;break;
caseTypeCode.Boolean:// boolean is basically an int, at least at this level
caseTypeCode.Int32:
opCode=OpCodes.Conv_Ovf_I4;break;
caseTypeCode.UInt64:
opCode=OpCodes.Conv_Ovf_I8_Un;break;
caseTypeCode.Int64:
opCode=OpCodes.Conv_Ovf_I8;break;
caseTypeCode.Single:
opCode=OpCodes.Conv_R4;break;
caseTypeCode.Double:
opCode=OpCodes.Conv_R8;break;
default:
handled=false;
break;
}
}
}
if(handled)
{// unbox as the data-type, then use IL-level convert
il.Emit(OpCodes.Unbox_Any,dataType);// stack is now [target][target][data-typed-value]
il.Emit(opCode);// stack is now [target][target][typed-value]
if(unboxTypeCode==TypeCode.Boolean)
{// compare to zero; I checked "csc" - this is the trick it uses; nice
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
if(handled)
{// unbox as the data-type, then use IL-level convert
il.Emit(OpCodes.Unbox_Any,dataType);// stack is now [target][target][data-typed-value]
il.Emit(opCode);// stack is now [target][target][typed-value]
if(unboxTypeCode==TypeCode.Boolean)
{// compare to zero; I checked "csc" - this is the trick it uses; nice
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
}
}
else
{// use flexible conversion
il.Emit(OpCodes.Ldtoken,nullUnderlyingType??unboxType);// stack is now [target][target][value][member-type-token]
il.EmitCall(OpCodes.Call,typeof(Type).GetMethod("GetTypeFromHandle"),null);// stack is now [target][target][value][member-type]
il.EmitCall(OpCodes.Call,typeof(Convert).GetMethod("ChangeType",newType[]{typeof(object),typeof(Type)}),null);// stack is now [target][target][boxed-member-type-value]
il.Emit(OpCodes.Unbox_Any,nullUnderlyingType??unboxType);// stack is now [target][target][typed-value]
}
}
else
{// use flexible conversion
il.Emit(OpCodes.Ldtoken,Nullable.GetUnderlyingType(unboxType)??unboxType);// stack is now [target][target][value][member-type-token]
il.EmitCall(OpCodes.Call,typeof(Type).GetMethod("GetTypeFromHandle"),null);// stack is now [target][target][value][member-type]
il.EmitCall(OpCodes.Call,typeof(Convert).GetMethod("ChangeType",newType[]{typeof(object),typeof(Type)}),null);// stack is now [target][target][boxed-member-type-value]
il.Emit(OpCodes.Unbox_Any,unboxType);// stack is now [target][target][typed-value]
if(nullUnderlyingType!=null)
{
il.Emit(OpCodes.Newobj,unboxType.GetConstructor(new[]{nullUnderlyingType}));// stack is now [target][target][typed-value]