Почему Вы не можете использовать пустой указатель в качестве ключа для Словаря <bool?, строка>?

По-видимому, Вы не можете использовать a null для ключа, даже если Ваш ключ является nullable типом.

Этот код:

var nullableBoolLabels = new System.Collections.Generic.Dictionary<bool?, string>
{
    { true, "Yes" },
    { false, "No" },
    { null, "(n/a)" }
};

... результаты в этом исключении:

Значение не может быть нулевым. Название параметра: ключ

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

[ArgumentNullException: Value cannot be null. Parameter name: key] System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) +44 System.Collections.Generic.Dictionary'2.Insert(TKey key, TValue value, Boolean add) +40
System.Collections.Generic.Dictionary'2.Add(TKey key, TValue value) +13

Почему платформа.NET позволила бы nullable тип для ключа, но не позволила бы нулевое значение?

67
задан devuxer 1 February 2010 в 17:57
поделиться

10 ответов

Этот вопрос заключается в том, что вы хотите связать некоторые данные с типами, а не с экземплярами типов. Я не уверен, что есть аккуратный способ сделать это в C #, но одна возможность использует статический словарь <Тип, строка []> на BaseRecord . Пример ниже, вы можете изменить это, добавив некоторые универсальные статические элементы на BaseECord для инициализации / доступа к именам записи (и добавить некоторую проверку ошибок ...):

using System;
using System.Collections.Generic;

namespace Records
{
    public class BaseRecord
    {
        public bool isDirty;
        public object[] itemArray;

        public static Dictionary<Type, string[]> columnNames = new Dictionary<Type, string[]>();
    }

    public class PeopleRec : BaseRecord
    {
        static PeopleRec()
        {
            string[] names = new string[2];
            names[0] = "FIRST_NAME";
            names[1] = "LAST_NAME";
            BaseRecord.columnNames[typeof(PeopleRec)] = names;
        }
    }

    public class DoWork<T> where T : BaseRecord
    {
        public void DisplayColumnNames()
        {
            foreach (string s in BaseRecord.columnNames[typeof(T)])
                Console.WriteLine("{0}", s);
        }

        public void DisplayItem(T t)
        {
            for (int i = 0; i < t.itemArray.Length; i++)
            {
                Console.WriteLine("{0}: {1}", BaseRecord.columnNames[typeof(T)][i], t.itemArray[i]);
            }
        }
    }

    class Program
    {
        public static void Main()
        {
            PeopleRec p = new PeopleRec
            {
                itemArray = new object[] { "Joe", "Random" }
            };

            DoWork<PeopleRec> w = new DoWork<PeopleRec>();
            w.DisplayColumnNames();
            w.DisplayItem(p);
        }
    }
}
-121--4460238-

Это расскажет вам то же самое, если бы у вас был словарь , ukeype Быть ссылочным типом, и вы пытались пройти null Как ключей, это не то, что влияет на только нулевой тип Bool? . Вы можете использовать любой тип в качестве ключа, отнуритель или нет.

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

Если вы хотите причину спецификации, это сводится к «ключу не может быть нулевой ссылкой» на MSDN .

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

36
ответ дан 24 November 2019 в 14:44
поделиться

Ключевое значение должно быть уникальным, поэтому ноль не может быть действительным ключом, так как ноль не указывает на отсутствие ключа.

Поэтому структура .Net не разрешает значение null и бросает исключение.

Что касается того, почему Nullable разрешено, а не ловит во время компиляции, я думаю, причина в том, что пункт where, который разрешает каждое T, за исключением Nullable, невозможен (по крайней мере, я не знаю, как этого добиться).

0
ответ дан 24 November 2019 в 14:44
поделиться

Ключи словаря не могут быть нулевыми в .NET, независимо от типа ключа (нулевой или нет).

Из MSDN: Пока объект используется в качестве ключа в словаре<(Of <(TKey, TValue>)>), он не должен изменяться никаким образом, влияющим на его хэш-значение. Каждый ключ в словаре<(Of <(TKey, TValue>)>) должен быть уникальным в соответствии со словарем сравнения равенства. Ключ не может быть нулевой ссылкой (Nothing в Visual Basic), но значение может быть, если тип TValue является типом ссылки. (http://msdn.microsoft.com/en-us/library/xfhwa508.aspx)

-1
ответ дан 24 November 2019 в 14:44
поделиться

код бит должен читать:

var my_json;
$.getJSON(my_url, function(json) {
  my_json = json;
});
-121--1069632-

Это будет сделано:

var json = (function () {
    var json = null;
    $.ajax({
        'async': false,
        'global': false,
        'url': my_url,
        'dataType': "json",
        'success': function (data) {
            json = data;
        }
    });
    return json;
})(); 

Основная проблема заключается в том, что $ .getJSON будет выполняться асинхронно, таким образом, ваш Javascript будет прогрессировать мимо выражения, которое вызывает его даже до его успешного обратного вызова, так что нет гарантий, что

Обратите внимание, в частности, на опцию «async»: false в приведенном выше вызове ajax. В руководстве указано:

По умолчанию все запросы отправляются асинхронный (т. е. установлено значение true по умолчанию). При необходимости синхронного запросы, установите для этой опции значение false. Обратите внимание, что синхронные запросы могут временно заблокировать браузер, отключение любых действий во время запрос активен.

-121--1069631-

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

Нулевое значение для типа значения null предназначено для представления нулевого значения - семантика предназначена для того, чтобы быть как можно более синонимичным ссылочному значению null. Было бы немного странно, если бы можно было использовать значение null, допускающее значение null, где нельзя было бы использовать ссылки null только из-за детализации реализации типов значений, допускающих значение null.

Это или словарь имеет:

if (key == null)

и они никогда не думали об этом на самом деле.

0
ответ дан 24 November 2019 в 14:44
поделиться

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

В C ++ вы часто должны выбрать ключ, который не будет использоваться - словарь использует эту клавишу, чтобы указать на удаленные и / или пустые записи. Например, у вас есть словарь , а после вставки записи вы его удаляете. Вместо того, чтобы запустить мусорную очистку прямо тогда и там, реструктурирую словарь и приводит к плохой производительности; Словарь просто заменит значение ключа с указанным вами ключом, в основном означает «Когда вы пересекаете словарь MemorySpace, притворяетесь в этом <ключ, значение> Пара не существует, не стесняйтесь перезаписываться , «

Такой ключ также используется в словарях, которые предварительно выделяют пространство в ведрах определенным образом - вам нужен ключ для« инициализации »ведер со вместо того, чтобы иметь флаг для каждой записи, которая указывает, или нет Содержимое действительны. Поэтому вместо того, чтобы иметь тройную <ключ, значение, инициализированное> , у вас будет кортеж <ключ, значение> с правилом, являющимся тем, что если ключ == just_key, то он не имеет был инициализирован - и, следовательно, вы не можете использовать joy_key в качестве допустимого значения ключа.

Вы можете увидеть такое поведение в Google Hashtable (словарь для вас .NET Люди :) В документации здесь: http://google-sparsehash.googlecode.com/svn/trunk/doc/dense_hash_map .html

Посмотрите на set_deleted_key и функций set_empty_key , чтобы получить то, о чем я говорю.

Я PAWER .NET использует NULL как уникальный delectele_key или just_key, чтобы выполнить эти сортировки изящных трюков, которые улучшают производительность.

14
ответ дан 24 November 2019 в 14:44
поделиться

Вы не можете использовать нулевой Bool? Поскольку нулевые типы должны действовать как ссылочные типы. Вы не можете использовать нулевую ссылку в качестве ключа словаря.

Причина, по которой вы не можете использовать нулевую ссылку в виде ключа словаря, вероятно, сводится к решению дизайна в Microsoft. Разрешение нулевых клавиш требует проверки на них, что делает внедрение более медленным и сложнее. Например, реализация должна будет избежать использования .equals или .GethashCode на нулевую ссылку.

Я согласен, что позволяя нулевые клавиши были бы предпочтительны, но уже слишком поздно, чтобы изменить поведение сейчас. Если вам нужен обходной путь, вы можете написать свой собственный словарь с разрешенными нулевыми клавишами, или вы могли бы написать структуру обертки, которая неявно преобразует в / из t и сделать, чтобы получить тип ключа для вашего словаря (т. Е. Струкцию обернут нулю и Ручка сравнения и перемешивания, поэтому словарь никогда не «видит» нулевой).

4
ответ дан 24 November 2019 в 14:44
поделиться

Ах, проблемы общего кода. Рассмотрим этот блок через Reflector:

private void Insert(TKey key, TValue value, bool add)
{
    int freeList;
    if (key == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
    }

Нет возможности переписать этот код так, чтобы он говорил "Nullable nulls are allowed, but don't allow reference types to be null".

Хорошо, а как насчет того, чтобы не позволить TKey быть "bool?". Опять же, в языке C# нет ничего, что позволило бы вам это сказать.

0
ответ дан 24 November 2019 в 14:44
поделиться

, не используемый NULL, является частью Договора в соответствии с страницей MSDN: http://msdn.microsoft.com/en-us/library/k7z0zy8k.aspx

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

1
ответ дан 24 November 2019 в 14:44
поделиться

Словари (основное описание)
Словарь - это общая (типизированная) реализация класса Hashtable, представленного в .NET framework 2.0.

Хэштейбл хранит значение, основанное на ключе (более конкретно - хэш ключа).
Каждый объект в .NET имеет метод GetHashCode
Когда вы вставляете пару ключ-значение в хэш-таблицу, вызывается GetHashCode для ключа.
Подумайте: вы не можете вызвать метод GetHashCode на null.

Так что насчет типов Nullable?
Класс Nullable - это просто обертка, позволяющая присваивать нулевые значения типам значений. По сути, обертка состоит из HasValue, который определяет, является ли тип нулевым или нет, и Value, содержащего значение типа значения.

Сложите их вместе, и что вы получите
.NET не очень заботит, что вы используете в качестве ключа в hashtable/dictionary.
Но когда вы добавляете комбинацию ключ-значение, она должна быть способна генерировать хэш ключа.
Не имеет значения, если ваше значение обернуто внутри Nullable, null.GetHashCode невозможно.

Свойство Indexer и методы Add словаря будут проверять наличие null и при обнаружении null будут выбрасывать исключение.

2
ответ дан 24 November 2019 в 14:44
поделиться

Я только что читал об этом; и, как ответил Эрик, я теперь считаю, что это неверно, не все строки автоматически Interned, и мне нужно было переопределить операцию равенства.


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

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

Это потому, что внутри .net все строки, содержащие одно и то же значение, присваиваются одной и той же ссылке. (это называется 'Interning')

таким образом, после выполнения:

{
string str1 = "AB";
string str2 = "A";
str1 += "C";
str2 += "BC";
}

str1 и str2 фактически указывают на одно и то же место в памяти! что делает их одним и тем же объектом; что позволяет словарю найти элемент, добавленный с помощью str1 в качестве ключа, используя str2.

хотя если вы:

{
char[3] char1;
char[3] char2;
char1[0] = 'A';
char1[1] = 'B';
char1[2] = 'C';
char2[0] = 'A';
char2[1] = 'B';
char2[2] = 'C';
}

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

-1
ответ дан 24 November 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: