Почему System.Decimal игнорирует проверенный/непроверенный контекст
Я просто снова наткнулся на System.Decimal
и попросил объяснить.
При выдаче значения типа System.Decimal
для какого-либо другого типа (то есть System.Int32
) ключевое слово checked
и -checked
компилятора -checked
похоже, игнорируются.
Для демонстрации ситуации я создал следующий тест:
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)); });
}
}
Все мои исследовательские подразделения теперь не привели к надлежащему объяснению этого явления или даже некоторой дезинформации, заявляющей, что она должна работать. Мои исследования уже включали спецификацию С#
Есть ли там кто-нибудь, кто может пролить свет на это?
Ответы
Ответ 1
checked
контекст относится к IL, испускаемому вашим кодом, - он в основном изменяет код операции, используемый для этих математических операций из непроверенной версии в проверенную версию. Он не может сделать это для decimal
поскольку decimal
не является примитивным и не имеет прямых кодов операций: все арифметические операции предварительно встроены в пользовательские операторы, точно так же, как если бы вы добавили свой собственный struct MyType
и добавили операторов для Это. Итак: все будет зависеть от того, будут ли настраиваемые операторы, определяемые decimal
выбирать и исключать OverflowException
или нет, в этом коде. Что вы не контролируете и не можете влиять на вашу сборку.
Это decimal
тип, который обеспечивает decimal
преобразования <===> int
. К тому времени, когда он вернется к вашему коду, где ключевое слово checked
может иметь эффект, он уже либо генерирует int
либо исключение.
К сожалению, поддержка пользовательского оператора С# не распространяется на возможность добавления отдельных проверочных/непроверенных реализаций операторов, к сожалению.
Ответ 2
Спецификация С# (раздел 12.7.14 Проверенные и непроверенные операторы) содержит список затронутых операторов и операторов. Операторов в вашем тесте нет в списке:
Следующие операции зависят от контекста проверки переполнения, установленного checked
и unchecked
операторами и операторами:
- Предопределенные операторы
++
и --
(§12.7.10 и §12.8.6), когда операнд имеет интегральный или перечислимый тип. - Предопределенный
-
унарный оператор (§12.8.3), когда операнд имеет целочисленный тип. - Предопределенные
+
, -
, *
и /
двоичные операторы (§12.9), когда оба операнда являются интегральными или перечисляемыми. - Явные числовые преобразования (§11.3.2) из одного интеграла или enumtype в другой интеграл или enumtype, или из
float
или double
в интеграл или enumtype.