Ho un codice come questo per emettere il codice IL che carica valori interi o stringa. Ma non so come aggiungere il tipo decimal
a quello. Non è supportato nel metodo Emit
. Qualche soluzione a questo?Emettere il codice IL per caricare un valore decimale
ILGenerator ilGen = methodBuilder.GetILGenerator();
if (type == typeof(int))
{
ilGen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value, CultureInfo.InvariantCulture));
}
else if (type == typeof(double))
{
ilGen.Emit(OpCodes.Ldc_R8, Convert.ToDouble(value, CultureInfo.InvariantCulture));
}
else if (type == typeof(string))
{
ilGen.Emit(OpCodes.Ldstr, Convert.ToString(value, CultureInfo.InvariantCulture));
}
Non funziona:
else if (type == typeof(decimal))
{
ilGen.Emit(OpCodes.Ld_???, Convert.ToDecimal(value, CultureInfo.InvariantCulture));
}
Edit: Bene, ecco quello che ho fatto:
else if (type == typeof(decimal))
{
decimal d = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
// Source: https://msdn.microsoft.com/en-us/library/bb1c1a6x.aspx
var bits = decimal.GetBits(d);
bool sign = (bits[3] & 0x80000000) != 0;
byte scale = (byte)((bits[3] >> 16) & 0x7f);
ilGen.Emit(OpCodes.Ldc_I4, bits[0]);
ilGen.Emit(OpCodes.Ldc_I4, bits[1]);
ilGen.Emit(OpCodes.Ldc_I4, bits[2]);
ilGen.Emit(sign ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
ilGen.Emit(OpCodes.Ldc_I4, scale);
var ctor = typeof(decimal).GetConstructor(new[] { typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte) });
ilGen.Emit(OpCodes.Newobj, ctor);
}
Ma non genera un codice operativo newobj
, ma invece nop
e stloc.0
. Il costruttore viene trovato e inoltrato alla chiamata Emit
. Cosa c'è che non va qui? Ovviamente viene generato un InvalidProgramException
quando si tenta di eseguire il codice generato perché lo stack è completamente incasinato.
A quanto pare (ma non prendere la mia parola per esso) per "carico decimali" Non c'è un codice operativo diretta, si caricano gli argomenti e chiama il costruttore decimali: vedi http : //stackoverflow.com/a/485834/266143 – CodeCaster
Vedere anche http://codeblog.jonskeet.uk/2014/08/22/when-is-a-constant-not-a-constant-when-its-a -decimale/. In breve: i decimali non sono tipi primitivi CLR e non esiste alcun codice operativo IL per il caricamento diretto. –
Vedere la mia modifica sopra per una soluzione non funzionante. – ygoe