Подтвердить что ты не робот

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?
    }
}
4b9b3361

Ответ 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
  }

и вы увидите разницу.