{// no IL level conversions to/from decimal; I guess we could use the static operators, but
// this feels an edge-case
handled=false;
}
else
{
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);
}
}
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]
}
}
if(nullUnderlyingType!=null)
if(nullUnderlyingType!=null)
{
{
il.Emit(OpCodes.Newobj,unboxType.GetConstructor(new[]{nullUnderlyingType}));// stack is now [target][target][typed-value]
il.Emit(OpCodes.Newobj,unboxType.GetConstructor(new[]{nullUnderlyingType}));// stack is now [target][target][typed-value]
il.Emit(OpCodes.Unbox_Any,to);// stack is now [target][target][typed-value]
}
elseif((op=GetOperator(from,to))!=null)
{
// this is handy for things like decimal <===> double
il.Emit(OpCodes.Unbox_Any,from);// stack is now [target][target][data-typed-value]
il.Emit(OpCodes.Call,op);// stack is now [target][target][typed-value]
}
else
{
boolhandled=false;
OpCodeopCode=default(OpCode);
switch(Type.GetTypeCode(from))
{
caseTypeCode.Boolean:
caseTypeCode.Byte:
caseTypeCode.SByte:
caseTypeCode.Int16:
caseTypeCode.UInt16:
caseTypeCode.Int32:
caseTypeCode.UInt32:
caseTypeCode.Int64:
caseTypeCode.UInt64:
caseTypeCode.Single:
caseTypeCode.Double:
handled=true;
switch(Type.GetTypeCode(via??to))
{
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;
}
break;
}
if(handled)
{
il.Emit(OpCodes.Unbox_Any,from);// stack is now [target][target][col-typed-value]
il.Emit(opCode);// stack is now [target][target][typed-value]
if(to==typeof(bool))
{// 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
{
il.Emit(OpCodes.Ldtoken,via??to);// 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,to);// stack is now [target][target][typed-value]