Unchecked -keyword в С#
Возможно, я нахожусь в основах, но я все еще изучаю эту вещь С# в школе. Я понимаю, что если я добавлю 1 к максимальному значению Integer, который 32 бит, результат будет отрицательным. Я прочитал, что С# предлагает проверенные и непроверенные ключевые слова для обработки переполнения. Проверенное ключевое слово - это что-то, я нашел полезным, но как насчет неконтролируемого ключевого слова? Я действительно не могу найти не очень полезное использование для блока unchecked -keyworded. Есть ли? Как разные два подхода отличаются друг от друга?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Practice_6
{
class Program
{
static void Main(string[] args)
{
int value = Int32.MaxValue;
value++;
//Approach 1 to make a decision
if (value > Int32.MaxValue) {
//Do something
}
value = Int32.MaxValue;
//Approach 2 to make a decision
unchecked {
value++;
//Do something
}
//What the difference between these two approaches to handle overflow?
}
}
Ответы
Ответ 1
ОБНОВЛЕНИЕ: этот вопрос был тема моего блога в апреле 2015 года; спасибо за интересный вопрос!
Ваш первый вопрос:
Ключевое слово checked
полезно, но как насчет ключевого слова unchecked
? Я действительно не могу найти для этого пользы. Есть ли?
Команда разработчиков С# не имеет привычки добавлять функции, которые не имеют никакого отношения к языку. (За исключением заметного оператора унарного плюса, самого бесполезного оператора в мире).
Ключевое слово unchecked имеет два основных варианта использования.
Во-первых, постоянная целочисленная арифметика всегда проверяется по умолчанию. Это может раздражать. Предположим, например, у вас есть код взаимодействия, и вы хотите создать константу для HRESULT E_FAIL:
const int E_FAIL = 0x80004005;
Это ошибка, потому что это число слишком велико, чтобы вписаться в int
. Но вы можете не использовать uint
. Вы можете подумать, я просто скажу
const int E_FAIL = (int)0x80004005;
Но это также является незаконным, поскольку по умолчанию всегда проверяется постоянная арифметика, включая конверсии.
Что вам нужно сделать, это отключить проверенную постоянную арифметику с помощью
const int E_FAIL = unchecked((int)0x80004005);
Во-вторых, арифметика по умолчанию для непостоянной целочисленной математики в С# не отмечена, потому что она быстрее, и потому что это то, что делают многие другие подобные языки. Однако С# позволяет поменять значение по умолчанию на проверочную арифметику для непостоянной целочисленной математики с помощью флага компилятора. Если вы это сделали, и вам нужно снова отключить его на временной основе, вам нужно использовать синтаксис блока или выражения unchecked
.
Третий вариант использования - использовать неконтролируемый блок как форму самодокументирующего кода, чтобы сказать: "Я знаю, что операция, которую я здесь делаю, может переполняться, и это хорошо со мной". Например, я часто пишу что-то вроде:
int GetHashCode()
{
unchecked
{
int fooCode = this.foo == null ? 0 : this.foo.GetHashCode();
int barCode = this.bar == null ? 0 : this.bar.GetHashCode();
return fooCode + 17 * barCode;
}
}
"Непроверенный" подчеркивает читателю, что мы полностью ожидаем, что умножение и добавление хеш-кодов могут переполняться, и что это нормально.
Второй вопрос:
Какая разница между этими двумя подходами для обработки переполнения?
Хороший вопрос.
Если в выбранном вами контексте вы имеете в виду: Я ожидаю, что арифметика всегда будет в пределах границ; если это не так, то моя программа имеет серьезную ошибку и должна быть прервана до того, как она наносит больше вреда миру, тогда вам не следует выполнять проверку переполнения вообще, потому что переполнений нет. Любое исключение должно прекратить выполнение программы; проверенный контекст просто заставляет выполнение работать, чтобы проверить правильность вашего кода.
Если в выбранном вами контексте вы имеете в виду , мне нужно, чтобы арифметика была в пределах границ, но я получил эти данные из ненадежного источника, и я слишком ленив, чтобы сделать проверку диапазона на нем, тогда вы должны поймать исключение, Тем не менее, лучшей практикой было бы проводить проверку диапазона и давать более значимую ошибку, если данные находятся за пределами допустимого диапазона, чем для того, чтобы среда выполнения обнаружила проблему и выбрала исключение переполнения. Я бы настоятельно рекомендовал проверку диапазона, а не исключение; не ленитесь.
Ответ 2
Не следует ожидать, что правильно написанный код будет зависеть от того, скомпилирован ли проект с отмеченным или непроверенным по умолчанию. Код, в котором неочевидное арифметическое поведение обертывания может представлять опасность для безопасности или стабильности системы, должно выполняться в контексте checked
. Код, который опирается на обертывание арифметического поведения, должен выполняться в контексте unchecked
. Код общего назначения, в котором не ожидается арифметических переполнений, но имел бы ограниченные последствия, если они это сделали, должен быть скомпилирован с использованием настройки уровня проекта. Затем может быть установлен параметр "Уровень проекта" для проверки или снятия флажка в виде компромисса между скоростью выполнения и своевременным захватом ошибок.
Если неожиданные переполнения не происходят, код будет работать быстрее в непроверенном режиме. Если, однако, некоторые вычисления дают поддельные значения, и неясно, почему может помочь перекомпиляция с проверкой переполнения. Это заставит код работать медленнее, но будет ловушка при первом ошибочном вычислении. Однако переключение проекта в режим проверки для такой цели возможно только в том случае, если те части проекта, которые полагаются на арифметическое поведение обертывания, выполняются в явном контексте unchecked
. В противном случае переключение режимов уровня проекта просто полностью разрушит программу.
Ответ 3
Я не совсем уверен в значениях производительности checked
и unchecked
. Теоретически unchecked
должен быть более совершенным, и это контекст по умолчанию. Если вы не обходите границы целых типов для какого-то специального алгоритма/бизнес-логики и т.д., Использование checked
редко необходимо/полезно/читаемо.
Как я уже сказал, unchecked
является контекстом по умолчанию, так зачем вам ключевое слово unchecked
? Можно было бы четко указать тип контекста, где существует высокая степень использования контекстов checked
. Другой - использовать контекст unchecked
внутри контекста checked
:
checked {
int a = 5 + 1231;
unchecked {
a += 221;
}
}
Возможно, ваш вопрос может быть причиной того, что контекст по умолчанию не установлен. Я предполагаю, что это выбор Microsoft.
Их отличие состоит в том, что контекст checked
проверяет, существует ли переполнение для каждой арифметической операции и возникает исключение, если есть переполнение.
Ответ 4
Из MSDN причина использования unchecked будет следующей:
Поскольку проверка переполнения требует времени, использование непроверенного кода в ситуациях, когда нет опасности переполнения, может повысить производительность. Однако, если переполнение является возможностью, необходимо использовать проверенную среду.
Ответ 5
Измените свои коды на:
int value = int.MaxValue;
unchecked
{
value++;
}
Console.WriteLine(value);
value = int.MaxValue;
checked
{
value++; // this will raise OverflowException
}
и вы увидите разницу.