2013-05-24 3 views
3

У меня есть следующий код:Странное поведение диапазона при использовании в качестве ключа в словаре

Dim dicMyHash As Dictionary 
Dim rngMyRange As Range 

' A1 is empty - although the outcome is the same in any case 
Set rngMyRange = Range("A1") 
Set dicMyHash = New Dictionary 

dicMyHash.Add Key:=rngMyRange(1), Item:=0 

Debug.Print dicMyHash.Exists(rngMyRange(1).Value) ' returns False 
Debug.Print rngMyRange(1) = rngMyRange(1).Value  ' returns True 

Такое поведение является несколько неожиданным. Есть ли какой-то тип кастинга в фоновом режиме? rngMyRange(1).Value возвращает имущество variant, тогда как rngMyRange(1) составляет rngMyRange.item(1), что составляет range. Однако, отбрасывая rngMyRange(1) к Variant дает те же результаты ..

Кроме того, добавление ключей является значением (так копия rngMyRange(1) передается в качестве ключа). Но все же я не могу понять, почему .Exists не находит ключа.

Заранее благодарю вас!

ответ

3

Так вот, у нас есть три различных значения передается вокруг:

  1. оригинальный диапазон.
  2. Range.Value, который является вариантом.
  3. Копия (1), которая является внутренней для словаря.

Если вы сравните их с равными знаками, они все одинаковы. Но согласно Dictionary.Exists они все разные.

Почему? Когда вы используете знак равенства с объектом, знак равенства заставляет объект вызывать его свойство по умолчанию. Свойством по умолчанию Range является Range.Value, поэтому r = r.Value, а также r = r.Offset(0, 0).

Но для словаря это не так уж умно. Подумайте об этом: Каждый вызов Dictionary.Exists вызовет каждый объект, используемый в качестве ключа для вызова его свойства по умолчанию.Это может стать очень дорогостоящим и потенциально может вызвать множество побочных эффектов. Таким образом, Dictionary.Exists проверяет следующее:

  1. Вы сравниваете объект с не объектом? Автоматический сбой.
  2. Вы сравниваете два не-объекта? Возврат a = b.
  3. Вы сравниваете два объекта? Возврат a Is b.

Так r не то же самое, как r.Value, так как один является объектом, а другой не является объектом. И если вы делаете экземпляр из r, например, с r.Offset(0, 0), это не то же самое, поскольку они все еще указывают на два разных объекта, даже если объекты имеют одинаковое содержимое.

Это, с другой стороны, будет работать, так как вы будете делать r в тот же объект как d.Keys(0):

Dim d As Scripting.Dictionary 
Dim r As Range 
Set r = [a1] 
Set d = New Dictionary 
d.Add r, 0 
Set r = d.Keys(0) 
Debug.Print d.Exists(r) 
+0

rdhs thanks - Поскольку 'Dictionary.Exists' работает так, как вы описываете выше, остальное имеет смысл (а также устанавливает в вашем ответе' r = d.Keys (0) '). – Ioannis

+1

Тем не менее, я использовал бы нечто более разумное как ключ, например 'r.Address'. – Chel

+0

Абсолютно. В моем контексте я храню пользовательские объекты в этом словаре и использую их имена (строки) в качестве ключей, которые я получаю из динамического диапазона с помощью 'range.value' (проверка с помощью' .exists' для дубликатов). В какой-то момент я упомянул ключ без «.value» и столкнулся с проблемой. Спасибо за подробное объяснение - очень полезно! – Ioannis

1

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

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

dicMyHash.Add Key:=rngMyRange(1).value, Item:=0 

он начинает работать, как вы Expect- как проверка точек возврата true.

Вы можете дополнительно проанализировать эту ситуацию в Locals Window во время отладки вашего кода.

+0

Привет KazJew, спасибо - хорошая точка на размеры. Да, передача значения действительно работает. Но заменяя все 'rngMyRange (1)' вхождения на 'rngMyRange (1,1)', все еще возвращает 'false', как раньше. Хорошая идея re 'Locals Window', даст ему шанс. – Ioannis

+0

Итак, передача 'rngMyRange (1,1)' все еще распознается как массив, но 'rngMyRange (1,1) .value' распознается как правильное значение, полученное с помощью' true' для обеих тестовых точек. –

+0

О да, я вижу суть. Я также отметил, что '.exists (rngMyrange (1,1))' также дает 'false'. Это потому, что 'rngMyrange (1,1)' копируется в словарь как 2-мерный массив? – Ioannis

0

Я не знаю, как вы кладете это использовать, но это будет возвращать True:

Sub test() 
Dim dicMyHash As Dictionary 
Dim rngMyRange As Range 

Set rngMyRange = Range("A1") 
Set dicMyHash = New Dictionary 

dicMyHash.Add Key:=rngMyRange(1).Value, Item:=0 ' assign it with Value 
Debug.Print dicMyHash.Exists(rngMyRange(1).Value) 
End Sub 

Итак вы будете иметь элемент с ключом Что бы ни в A1.

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

+0

Привет, Doug thanks-я использую 'значение' нормально, просто интересно, почему' Range', похоже, не работает должным образом как «Ключ». Также отмечено, что '.Exists (rngMyRange (1))' возвращает false, когда 'rngMyRange (1)' является 'Key', и задавался вопросом, почему это так. Но да, я придерживаюсь использования' value'. – Ioannis

+2

Мне любопытно, почему в нижней нити. –

+0

Я поддержал, исходя из того, что приведенный выше ответ обеспечивает обходное решение. – Ioannis

Смежные вопросы