término que por oposición masculino masculina marcado linguistica habla género genero generico femenino definicion condición c# .net

c# - que - ¿Por qué System.Decimal ignora el contexto marcado/no marcado?



por que se habla en masculino (3)

Acabo de tropezar con un sistema. Una vez más la rareza decimal y busco una explicación.

Al emitir un valor de tipo System.Decimal a algún otro tipo (es decir, System.Int32 ), la palabra clave checked y la opción del compilador -checked parecen ignorarse.

He creado la siguiente prueba para demostrar la situación:

public class UnitTest { [Fact] public void TestChecked() { int max = int.MaxValue; // Expected if compiled without the -checked compiler option or with -checked- Assert.Equal(int.MinValue, (int)(1L + max)); // Unexpected // this would fail //Assert.Equal(int.MinValue, (int)(1M + max)); // this succeeds Assert.Throws<OverflowException>(() => { int i = (int)(1M + max); }); // Expected independent of the -checked compiler option as we explicitly set the context Assert.Equal(int.MinValue, unchecked((int)(1L + max))); // Unexpected // this would fail //Assert.Equal(int.MinValue, unchecked((int)(1M + max))); // this succeeds Assert.Throws<OverflowException>(() => { int i = unchecked((int)(1M + max)); }); // Expected independent of the -checked compiler option as we explicitly set the context Assert.Throws<OverflowException>(() => { int i = checked((int)(1L + max)); }); // Expected independent of the -checked compiler option as we explicitly set the context Assert.Throws<OverflowException>(() => { int i = checked((int)(1M + max)); }); } }

Toda mi unidad de investigación ahora no condujo a una explicación adecuada para este fenómeno o incluso a cierta información errónea afirmando que debería funcionar . Mi investigación ya incluía la especificación de C #

¿Hay alguien por ahí que pueda arrojar algo de luz sobre esto?


El CLR ofrece instrucciones de IL para operaciones aritméticas simples como add ( add ), sub (restar), mul (multiplicación), div (división).

Por ejemplo, tomemos una instrucción de add , que suma dos valores juntos. La instrucción de add no realiza ninguna comprobación de desbordamiento, pero hay una instrucción llamada add.ovf , que también agrega dos valores, pero arrojará una OverflowException si se produce un desbordamiento.

Por lo tanto, cuando esté utilizando el operador checked , la instrucción o el conmutador del compilador, usará la versión de "comprobación de desbordamiento" de la instrucción de add ( add.ovf ).

Recuerda que esto solo funciona para un "Tipos primitivos" .

Pero con los decimal las cosas son poco diferentes. CLR no considera el tipo decimal como un tipo primitivo (aunque sí lo tienen los lenguajes de programación como c # o visual basic), lo que significa que CLR no tiene instrucciones IL que saben cómo manipular decimal valor decimal . Si busca un tipo decimal en .NET Framework SDK Documantation o en el código fuente en ReferenceSources , notará que hay métodos llamados Add, Subtract, Multiply, Divide, etc.. y métodos de sobrecarga de operadores para +, -, *, /, etc

Cuando compila un código que usa decimal , el compilador generará un código para llamar a miembros decimal para realizar la operación real. Además, como no hay instrucciones de IL para manipular valores decimal , los modificadores / sentencias / compiladores marcados / no marcados no tienen efecto. Las operaciones con valores decimal siempre emitirán una OverflowException si la operación no se puede realizar de manera segura .


El contexto checked relaciona con el IL emitido desde su código: básicamente cambia el código de operación utilizado para esas operaciones matemáticas de la versión no verificada a la versión marcada. No puede hacer eso para el decimal porque el decimal no es un primitivo , y no tiene códigos de operación directos: todas las operaciones aritméticas están struct MyType en operadores personalizados, exactamente como lo serían si agregaras tu propio struct MyType y operadores agregados para eso. Entonces: todo dependerá de si los operadores personalizados definidos por decimal eligen detectar y lanzar OverflowException o no, en ese código . Lo que no controlas, y no puedes influir en tu construcción.

Es el tipo decimal que proporciona las conversiones de decimal <===> int . Cuando vuelva a su código, donde la palabra clave checked podría tener un efecto, ya es un int o se ha lanzado una excepción.

Lamentablemente, el soporte del operador personalizado de C # no se extiende a permitirle agregar implementaciones de operador marcadas / no marcadas por separado.


Especificación de C # (sección 12.7.14 Los operadores marcados y no verificados) contiene una lista de operadores afectados y declaraciones. Los operadores en su prueba no están en la lista:

Las siguientes operaciones se ven afectadas por el contexto de verificación de desbordamiento establecido por los operadores y declaraciones checked y unchecked checked :

  • Los operadores predefinidos de ++ y -- (§12.7.10 y §12.8.6), cuando el operando es de una integral o enumtype.
  • El operador predefinido - unario (§12.8.3), cuando el operando es de un tipo integral.
  • Los operadores predefinidos + , - , * y / binarios (§12.9), cuando ambos operandos son integrales o enumtypes.
  • Conversiones numéricas explícitas (§11.3.2) de una integral o enumtype a otra integral o enumtype, o de float o double a una integral o enumtype.