Nice programing

null을 사전의 키로 사용할 수없는 이유

nicepro 2020. 11. 15. 11:48
반응형

null을 사전의 키로 사용할 수없는 이유?


분명히 null키가 nullable 형식이더라도 키에 대해 사용할 수 없습니다 .

이 코드 :

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

...이 예외의 결과 :

값은 null 일 수 없습니다. 매개 변수 이름 : 키

설명 : 현재 웹 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다. 오류 및 코드에서 오류가 발생한 위치에 대한 자세한 정보는 스택 추적을 검토하십시오.

[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 형식을 허용하지만 null 값은 허용하지 않는 이유는 무엇입니까?


당신이이 있다면 그것은 당신에게 같은 것을 말할 것 Dictionary<SomeType, string>, SomeType참조 형식 인, 당신은 통과하려고 null뭔가 같은 단지 nullable 형식에 영향을 미치는되지 않습니다 키로 bool?. null 허용 여부에 관계없이 모든 유형을 키로 사용할 수 있습니다.

그것은 모두 당신이 실제로 비교할 수 없다는 사실로 귀결 nulls됩니다. null다른 객체와 비교되도록 설계된 속성 인 키 에 넣을 수없는 논리 null참조 를 비교하는 것이 일관성이 없다는 것 입니다.

사양에서 이유를 원하는 경우 MSDN 의 "A key cannot be a null reference"로 요약됩니다 .

가능한 해결 방법의 예를 원한다면 null 키를 허용하는 IDictionary 구현 필요 와 유사한 작업을 시도 할 수 있습니다.


.NET Framework가 특정 방식으로 작동하는 방법과 이유를 완전히 이해하려면 종종 C ++ 방법론과 기술로 돌아 가야합니다.

C ++에서는 종종 사용되지 않는 키를 선택해야합니다. 사전은이 키를 사용하여 삭제되거나 비어있는 항목을 가리 킵니다. 예를 들어 사전이 <int, int>이고 항목을 삽입 한 후 삭제합니다. 가비지 정리를 바로 실행하는 대신 사전을 재구성하여 성능을 저하시킵니다. 사전은 KEY 값을 이전에 선택한 키로 대체합니다. 기본적으로 "사전 메모리 공간을 순회 할 때이 <key,value>쌍이 존재하지 않는 것처럼 가정 하고 덮어 십시오."라는 의미입니다.

이러한 키는 특정 방식으로 버킷의 공간을 사전 할당하는 사전에서도 사용됩니다. 각 항목에 대한 내용이 유효한지 여부를 나타내는 플래그를 갖는 대신 버킷을 "초기화"하는 키가 필요합니다. 따라서 트리플을 갖는 대신 key == empty_key이면 초기화되지 않았으므로 empty_key를 유효한 KEY 값으로 사용할 수 없다는 규칙 <key, value, initialized>이있는 튜플 <key, value>이 있습니다.

http://google-sparsehash.googlecode.com/svn/trunk/doc/dense_hash_map.html 문서의 Google 해시 테이블 (.NET 사용자를위한 사전 :)에서 이러한 종류의 동작을 볼 수 있습니다.

상기 봐 set_deleted_keyset_empty_key내가 무슨 말 얻을 기능.

.NET은 성능을 향상시키는 이러한 종류의 멋진 트릭을 수행하기 위해 고유 한 deleted_key 또는 empty_key로 NULL을 사용합니다.


널 부울을 사용할 수 없습니까? nullable 형식은 참조 형식처럼 작동하기 때문입니다. null 참조를 사전 키로 사용할 수도 없습니다.

null 참조를 사전 키로 사용할 수없는 이유는 아마도 Microsoft의 설계 결정 때문일 것입니다. null 키를 허용하려면 해당 키를 확인해야하므로 구현이 느리고 복잡해집니다. 예를 들어 구현시 null 참조에서 .Equals 또는 .GetHashCode를 사용하지 않아야합니다.

null 키를 허용하는 것이 바람직하다는 데 동의하지만 지금 동작을 변경하기에는 너무 늦었습니다. 해결 방법이 필요하면 허용 된 null 키를 사용하여 자체 사전을 작성하거나 T로 /에서 암시 적으로 변환하여 사전의 키 유형으로 만드는 래퍼 구조체를 작성할 수 있습니다 (즉, 구조체는 null 및 비교 및 해싱을 처리하므로 사전은 null을 '보지'않습니다.)


근본적인 이유는 없습니다. HashSet은 null을 허용하고 HashSet은 단순히 키가 값과 동일한 유형 인 사전입니다. 따라서 실제로는 null 키가 허용되어야했지만 지금 변경하려면 중단 될 것이므로 우리는 계속 붙어 있습니다.


사전 (기본 설명)
사전은 .NET 프레임 워크 2.0에 도입 된 Hashtable 클래스의 일반 (형식화 된) 구현입니다.

해시 테이블은 키 (보다 구체적으로 키의 해시)를 기반으로 값을 저장합니다.
.NET의 모든 개체에는 GetHashCode.
해시 테이블에 키 값 쌍을 삽입하면 키에서이 GetHashCode호출됩니다.
생각해보십시오 :에서 GetHashCode메서드를 호출 할 수 없습니다 null.

그렇다면 Nullable 유형은 어떻습니까? 클래스는 단순히 래퍼 널 값 value 타입에 할당 될 수 있도록. 기본적으로 래퍼 는 null인지 아닌지를 알려주 부울과 값 유형의 값을 포함하는으로 구성됩니다.
NullableHasValueValue

조합하면 무엇을 얻을 수 있습니까?
.NET은 해시 테이블 / 사전에서 키로 사용하는 것을 실제로 신경 쓰지 않습니다.
그러나 키 값 조합을 추가 할 때 키의 해시를 생성 할 수 있어야합니다.
값이 Nullablenull 내부에 래핑되어 있는지 여부는 중요하지 않습니다 .GetHashCode는 불가능합니다.

Dictionary의 Indexer 속성 및 Add 메서드는 null을 확인하고 null을 찾으면 예외를 throw합니다.


null을 사용하지 않는 것은 MSDN 페이지 http://msdn.microsoft.com/en-us/library/k7z0zy8k.aspx 에 따른 계약의 일부입니다 .

이유는 null을 유효한 값으로 사용하면 아무 이유없이 코드가 복잡해지기 때문이라고 생각합니다.


키 값은 고유해야하므로 null은 키가 없음을 나타내므로 유효한 키가 될 수 없습니다.

그래서 .Net 프레임 워크 null 값을 허용 하지 않고 예외를 throw합니다.

왜 Nullable이 허용되고 컴파일 타임에 catch하지 않는 한, 그 이유는 Nullable을 제외한 모든 where항목을 허용 하는 절이 불가능 하기 때문이라고 생각 T합니다 (적어도 그것을 달성하는 방법을 모릅니다).


아, 제네릭 코드의 문제. 리플렉터를 통해이 블록을 고려하십시오.

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

"Nullable null은 허용되지만 참조 유형이 null이되도록 허용하지 않습니다"라고이 코드를 다시 작성할 수있는 방법은 없습니다.

좋아, 그래서 TKey가 "bool"이되는 것을 어떻게 허용하지 않는가? 다시 말하지만, C # 언어에는 그렇게 말할 수있는 것이 없습니다.


사전은 GetHashCode 메서드가 없기 때문에 다양한 이유로 null 참조 형식을 허용 할 수 없습니다.

A null value for nullable value type is meant to represent a null value – the semantics are meant to be as synonymous with a reference null as possible. It would be slightly odd if you could use null nullable value where you couldn't use null references just because of an implementation detail of nullable value types.

Either that or Dictionary has:

if (key == null)

and they never really thought about it.


Dictionary keys can't be null in .NET, regardless of the type of the key (nullable or otherwise).

From MSDN: As long as an object is used as a key in the Dictionary<(Of <(TKey, TValue>)>), it must not change in any way that affects its hash value. Every key in a Dictionary<(Of <(TKey, TValue>)>) must be unique according to the dictionary's equality comparer. A key cannot be null reference (Nothing in Visual Basic), but a value can be, if the value type TValue is a reference type. (http://msdn.microsoft.com/en-us/library/xfhwa508.aspx)


I've just been reading up on this; and as Eric replied, I now believe this is incorrect, not all strings are automatically Interned, and I needed to override the equality operation.


This bit me when I converted a dictionary from using a string as a key to an array of bytes.

I was in the vanilla C mindset of a string simply being an array of characters, so it took me a while to figure out why a string built by concatenation worked as a key for lookups while a byte array built in a loop did not.

It's because internally .net assigns all strings that contain the same value to the same reference. (it's called 'Interning')

so, after running:

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

str1 and str2 actually point to the exact same place in memory! which makes them the same onject; which allows a dictionary to find an item added with str1 as a key by using str2.

while if you:

{
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 and char2 are distinct references; if you use char1 to add an item to a dictionary, you cannot use char2 to look it up.

참고URL : https://stackoverflow.com/questions/2174692/why-cant-you-use-null-as-a-key-for-a-dictionarybool-string

반응형