Должен ли я проверить наличие определенного ключа в словаре, прежде чем получить к нему доступ? - PullRequest
10 голосов
/ 21 июля 2009

Должен ли я проверить, присутствует ли конкретный ключ в словаре , если я уверен, что он будет добавлен в словарь к тому времени, когда я достигну кода для доступа к нему?

Есть два способа получить доступ к значению в словаре

  1. проверка метода ContainsKey. Если он возвращает true, тогда я получаю доступ, используя индексатор [ключ] объекта словаря.

или

  1. TryGetValue, который будет возвращать true или false, а также возвращать значение через выходной параметр.

(2-й будет лучше, чем 1-й, если я хочу получить значение. Тест .)

Однако, если я уверен, что функция, которая обращается к глобальному словарю, обязательно будет иметь ключ, тогда я все равно должен проверять, используя TryGetValue, или без проверки, я должен использовать indexer [].

Или я никогда не должен предполагать это и всегда проверять?

Ответы [ 9 ]

18 голосов
/ 21 июля 2009

Используйте индексатор, если ключ должен присутствовать - если он отсутствует, он выдаст соответствующее исключение, которое является правильным поведением, если отсутствие ключа указывает на ошибку.

Если действительно, что ключ отсутствует, используйте TryGetValue и реагируйте соответствующим образом.

(также примените советы Марка о безопасном доступе к общему словарю.)

10 голосов
/ 21 июля 2009

Если словарь является глобальным (статическим / общим), вы должны синхронизировать доступ к нему (это важно; в противном случае вы можете повредить его).

Даже если ваш поток только читает данные, он должен учитывать блокировки других потоков, которые могут его редактировать.

Тем не менее, если вы уверены, что элемент есть, с индексатором все будет в порядке:

Foo foo;
lock(syncLock) {
    foo = data[key];
}
// use foo...

В противном случае полезный шаблон - проверить и добавить в тот же замок:

Foo foo;
lock(syncLock) {
    if(!data.TryGetValue(key, out foo)) {
        foo = new Foo(key);
        data.Add(key, foo);
    }
}
// use foo...

Здесь мы только добавляем элемент, если его там не было ... но внутри того же замка .

2 голосов
/ 21 июля 2009

Всегда проверяйте. Никогда не говори никогда. Я предполагаю, что ваше приложение не настолько критично для производительности, чтобы вам приходилось экономить время проверки.

СОВЕТ: Если вы решили не проверять, по крайней мере, используйте Debug.Assert (dict.ContainsKey (key)); Это будет скомпилировано только в режиме отладки, ваша сборка выпуска не будет содержать его. Таким образом, вы можете по крайней мере иметь проверку при отладке.

Тем не менее: если возможно, просто проверьте это: -)

РЕДАКТИРОВАТЬ: здесь были некоторые заблуждения. Под «всегда проверять» я имел в виду не только использование if где-либо. Правильная обработка исключения также была включена в это. Итак, чтобы быть более точным: никогда не принимайте ничего как должное, ожидайте неожиданного. Проверьте с помощью ContainsKey или обработайте потенциальное исключение, но сделайте что-нибудь, если элемент не содержится.

1 голос
/ 10 июля 2011

Конечно, ответ «все зависит от ситуации». Вы должны уравновесить риск того, что ключ будет отсутствовать в словаре (низкий для небольших систем, где доступ к данным ограничен, где вы можете полагаться на порядок выполнения, больший для более крупных систем, несколько программистов обращаются к одному и тому же). данные, особенно с доступом для чтения / записи / удаления, когда речь идет о потоках, а порядок не может быть гарантирован или если данные происходят извне, и чтение может прерваться) с воздействием риска (критические для безопасности системы, коммерческие выпуски или системы, которые бизнес будет использовать полагайтесь на то, что создано для развлечения, на разовую работу и / или только для вашего использования), а также на любые требования к скорости, размеру и лени.

Если бы я создавал систему управления железнодорожной сигнализацией, я бы хотел быть в безопасности от всех возможных и невозможных ошибок и от ошибок в обработке ошибок и т. Д. (2-й закон Мерфи: «что не может пойти не так, как надо») пойдет не так ».) Если я собираюсь смешать вещи ради забавы, даже если размер и скорость не являются проблемой, я буду НАМНОГО более раскован с такими вещами - я захочу перейти к забавным вещам.

Конечно, иногда это самое интересное само по себе.

1 голос
/ 21 июля 2009

Лично я бы проверил, есть ли ключ, независимо от того, уверены ли вы в этом, некоторые могут сказать, что эта проверка излишня, и что словарь выдаст исключение, которое вы можете поймать, но imho вам не следует полагаться это исключение, вы должны проверить себя и затем либо выдать свое собственное исключение, которое означает что-то, либо объект результата с флагом успеха и причиной внутри ... механизм отказа действительно зависит от реализации.

0 голосов
/ 21 июля 2009

Я думаю, что у Марка и Джона это (как обычно) довольно засеяно. Поскольку вы также упоминаете производительность в своем вопросе, возможно, стоит подумать о том, как заблокировать словарь.

Простой lock сериализует весь доступ для чтения, который может быть нежелателен, если чтение выполняется очень часто, а записи относительно мало В этом случае лучше использовать ReaderWriterLockSlim. Недостатком является то, что код немного сложнее, а запись немного медленнее.

0 голосов
/ 21 июля 2009

Если вы знаете, что словарь обычно содержит ключ, вам не нужно проверять его, прежде чем получить к нему доступ.

Если что-то не так и словарь не содержит элементов, которые он должен, вы можете разрешить словарю генерировать исключение. Единственная причина проверки ключа в первую очередь заключается в том, что вы хотите самостоятельно решить эту проблемную ситуацию без получения исключения. Позволение словарю генерировать исключение и ловить, что, тем не менее, является совершенно правильным способом справиться с ситуацией.

0 голосов
/ 21 июля 2009

С точки зрения производительности, есть 2 направления мысли.

1) Избегайте исключений, где это возможно, так как исключения являются дорогостоящими - то есть проверьте, прежде чем пытаться извлечь конкретный ключ из словаря, существует он или нет. На мой взгляд, лучше подходить, если есть все шансы, что он может не существовать. Это предотвратит довольно распространенные исключения.

2) Если вы уверены, что объект будет существовать там в 99% случаев, не проверяйте его наличие, прежде чем получить к нему доступ. В 1% случаев, когда его не существует, будет сгенерировано исключение, но вы сэкономили время для остальных 99% времени, не проверяя.

То, что я говорю, это оптимизировать для большинства, если есть четкое. Если существует какая-либо реальная степень неопределенности в отношении существующего элемента, проверьте перед извлечением.

0 голосов
/ 21 июля 2009

TryGetValue - это тот же код, что и для индексации по ключу, за исключением того, что первый возвращает значение по умолчанию (для параметра out), где последний создает исключение. Используйте TryGetValue, и вы получите последовательные проверки без потери производительности.

Редактировать: Как сказал Джон, если вы знаете, что у него всегда будет ключ, вы можете проиндексировать его и позволить ему выбросить соответствующее исключение. Однако, если вы можете предоставить более полную контекстную информацию, отправив ее себе с подробным сообщением, это было бы предпочтительным.

...