Поиск  Пользователи  Правила 
Закрыть
Логин:
Пароль:
Забыли свой пароль?
Регистрация
Войти
 
Страницы: 1 2 След.
RSS
Оператор "Is" в VBA возвращает "False" для одинаковых диапазонов
 
Доброго времени суток!

Хочу разобраться в работе оператора Is в VBA.

Следующие выражения возвращают True:
Код
ThisWorkbook Is ThisWorkbook
ActiveSheet Is ActiveSheet
Но с объектом Range дела обстоят иначе:
Код
Range("A1") Is Range("A1")
- данное выражение принимает значение False.

В связи с этим есть два вопроса:
1) Почему?
2) Есть ли ещё подобные объекты в модели VBA, для которых оператор Is работает "нелогично"?

P.S. О возможности сравнения адресов диапазонов знаю, интересна здесь именно механика оператора Is.

Спасибо!
 
Код
Sub IsIsIs()
    Dim rRng As Range
    Debug.Print ThisWorkbook Is ThisWorkbook
    Debug.Print ActiveSheet Is ActiveSheet
    
    Set rRng = Range("A1")
    Debug.Print rRng Is rRng
    Set rRng = Nothing
End Sub
 
vikttur,

И в это же время, изменив 7-ю строку:
Код
Debug.Print rRng Is Range("A1")
- будет False. Хочется понять причину.
 
Оператор Is работает с обектами. Но когда оператору подсовывают Range, он в растеряности...

Насколько я понимаю...
Книга, лист - по умолчанию всегда объект.  А вот указание ссылки на диапазон может означать и объект, и значение (одно или несколько). Надо явно объяснить, что мы хотим от Range

Ошибочно. см. ниже
 
vikttur,
Но Is работает только с объектами. Значение для Range - это просто свойство по умолчанию. И если сравнивать именно значения диапазона с помощью Is, возникнет ошибка.
 
Как я понимаю, сравнивать нужно не сам диапазон, а какое-либо свойство диапазона.
 
Цитата
Оператор Is определяет, ссылаются ли две объектные ссылки на один и тот же объект
:)
Is размышляет:
rRng ссылается на диапазон Range("A1")? Да.
Какая-то неопределенная ссылка ссылается на тот же объект, что и ссылка rRng? Как я скажу, если не знаю, что это мне подсунули. А я, как на зло, не умею определять, что это... Пока будет Нет.

Вместе с Is чай не пил, только догадки. Придут те, кто с оператором на короткой ноге, расскажут )

P.S.
Плохо я о нем думал... Похоже, оператор понимает,  с чем имеет дело:
Код
    Debug.Print Range("A1") Is Nothing
    Debug.Print rRng Is Nothing
 
Юрий М,
Можно =) Вопрос в том - почему это происходит и есть ли ещё объекты, для которых это происходит.
 
Полагаю, свойство Range при каждом обращении создает новый объект, поэтому для Is они разные.
 
Вот оно что... Похоже на правду.
Почему так же не происходит с листом?
 
Цитата
vikttur написал: Похоже на правду.
Тест:
Код
Sub sub1()
  Dim R1 As Range
  Dim R2 As Range
  Set R1 = Range("A1")
  Set R2 = Range("A1")
  MsgBox ObjPtr(R1) & vbCr & ObjPtr(R2)
End Sub
Цитата
vikttur написал: не происходит с листом
Видимо, потому что лист как-бы член коллекции, а диапазон вычисляется в зависимости от параметра
 
Alec Perle, спасибо! Подтверждается:
Код
Sub sub1()
    Dim sht1 As Worksheet, sht2 As Worksheet
    Dim R1 As Range, R2 As Range
    
    Set sht1 = ActiveSheet: Set sht2 = ActiveSheet
    Set R1 = Range("A1"): Set R2 = Range("A1")
    MsgBox ObjPtr(sht1) & "---" & ObjPtr(sht1) & vbCr & _
    ObjPtr(R1) & "---" & ObjPtr(R2)
End Sub
 
Собственно это одна из причин, почему  рекомендуется использовать  With или Set при множественном применении ссылок. Это позволяет не просто сократить запись, но и однократно создавать ссылку на объект.
просто сравните разницу
Код
Sub test1()
    Dim a
    
    Set r = Range("a1")
    t = Timer
    For i = 1 To 1000000
        a = r.Value
    Next
    Debug.Print Timer - t
    
    With Range("a1")
        t = Timer
        For i = 1 To 1000000
            a = .Value
        Next
        Debug.Print Timer - t
    End With
    
    t = Timer
    For i = 1 To 1000000
        a = Range("a1").Value
    Next
    Debug.Print Timer - t
    
End Sub
Изменено: БМВ - 13 Дек 2019 00:04:35
По вопросам из тем форума, личку не читаю.
 
Да уж....
А я вообще не использовал With. Более того, старательно вычищал от With используемые сторонние коды. Мне конструкции с ними кажутся неудобочитаемыми.
Теперь буду знать...
Конструкцию типа Set R=Range иногда использую, но только из-за удобочитаемости.
 
Цитата
ControlAltExcel написал:
Вопрос в том - почему это происходит
У объекта "Range" есть свойство по умолчанию = "Value"
Сколько раз вы и другие (люди) писали Range("A1") без ".Value" при написании кода ? Один, два ... никогда ?
:)

Как уже написано выше (vikttur) и тоже в "F1" (быстрая помощь, контекстна):
Код
Sub abc_xyz()
    Dim a1 As Object, b1 As Object, c1 As Object
    
    Set a1 = Range("A1")
    Set b1 = a1
    Set c1 = a1
    
    MsgBox b1 Is c1
    
    'If object1 and object2 both refer to the same object, result is True
End Sub
 
ocet p, скорее всего вы сперва к истине приблизили, а после от нее отошли пояснениями с Value.
В отличии от Range  Книга, лист... к моменту определения присутствуют, как отдельные объекты. То есть мы сперва создаем например лист, тем самым появляется объект. Ссылки на эти объекты будут всегда одинаковы. Другое дело range или cell. Не создается автоматически миллиарды объектов для отдельных ячеек, тем более фантазийные "Represents a cell, a row, a column, a selection of cells containing one or more contiguous blocks of cells, or a 3D range". Каждый раз конструкция создает новый объект и не смотря на то что все его свойства и значения будут одинаковыми Объекты будут разными.
По вопросам из тем форума, личку не читаю.
 
БМВ, не загонялся по скорости выполнения в именно этом сравнении, но в #13 сообщении отличный пример. Это хорошо, что я последнее время привык к With. Всегда стараюсь его применять.
Знания и технологии принадлежат человечеству, и каждый сам решает делиться ими или исчезнуть вместе с ними.
 
При обращении к листам и диапазонам создаются всегда разные адреса в памяти:
Код
Sub IsNotIs()
    Dim rc As Range, rc2 As Range
    Set rc = Range("A1")
    Set rc2 = Range("A1")
    Debug.Print ObjPtr(rc)
    Debug.Print ObjPtr(Range("A1"))
    Debug.Print ObjPtr(rc2)
    Debug.Print rc Is Range("A1")
End Sub

а это значит, что IS будет считать их разными, т.к. сравнивает по тому же принципу, что и ObjPtr. Поэтому в выше приведенном коде они не будет равны. Поэтому сравнивать объекты некоторых коллекций Excel лучше по именам и полным адресам:
Код
Sub IsAddr()
    Dim rc As Range
    Set rc = Range("A1")
    Debug.Print ObjPtr(rc)
    Debug.Print ObjPtr(Range("A1"))
    Debug.Print rc.Address(external:=True) = Range("A1").Address(external:=True)
End Sub
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий(The_Prist) Щербаков, мне кажется про листы это лишнее. Только к диапазонам.
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ: сравните разницу
Код
' r as Variant
 2,035156 
 1,753906 
 12,25391 

' r as Range
 1,925781 
 1,773438 
 12,03125
 
' r as Range + Value2
1,734375 
 1,742188 
 12,16016
«Тот, кто несет фонарь, спотыкается чаще, чем тот, кто идет следом.»
Иоганн Пауль Фридрих Рихтер
 
OFF
Цитата
Alemox: я последнее время привык к With. Всегда стараюсь его применять
не настолько, как эту конструкцию любит МатросНаЗебре  :D
«Тот, кто несет фонарь, спотыкается чаще, чем тот, кто идет следом.»
Иоганн Пауль Фридрих Рихтер
 
Цитата
БМВ написал:
кажется про листы это лишнее
ну как бы...И да и нет :) Тут тема уже иная, согласен. Просто вспомнилось и надо было бы сразу пояснить до кучи, что имею ввиду под листами. Это по сути будет вдогонку текущей теме на всякий случай.
Не все знают, что не все листы одинаковые: есть листы рабочие(Worksheet), есть листы диаграмм(Chart), есть листы макросов и диалогов.
Так вот, если пытаться сравнить с листа макросов, например, то получим-таки False:
Код
Sub IsNotIs2()
    Debug.Print ObjPtr(ActiveCell.Worksheet)
    Debug.Print ObjPtr(ActiveSheet)
    Debug.Print ActiveCell.Worksheet Is ActiveSheet
End Sub
потому что ActiveCell.Worksheet не всегда одно и тоже, что ActiveSheet
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
OFF
Цитата
Jack Famous написал:
не настолько,  как  эту конструкцию любит МатросНаЗебре  
Действительно, иногда "любовь" выходит за разумные рамки :)
 
Jack Famous, в такой записи, которую вы показали в #21, вполне резонно использовать. У меня последнее время в этой строчке такая же запись  :D
Знания и технологии принадлежат человечеству, и каждый сам решает делиться ими или исчезнуть вместе с ними.
 
Jack Famous, Алексей, ну в данном случае выигрыш конечно незаметен будет, но в целом один раз указываем объект, а не два. Нормальная практика. Я и вложенные with частенько использую.
Что касаемо замеров, пример был направлен больше на заметное отставание постоянного применения Range("a1"). Он конечно искуственный ибо вероятность такого применения на больших циклах мала, но как говорится тут , там поджались, глядишь и ресурса меньше нужно.
По вопросам из тем форума, личку не читаю.
 
Цитата
Alemox: в такой записи, которую вы показали в #21, вполне резонно использовать
почему? Не короче точно. Быстрее? Едва ли… По собственному опыту уяснил, что работа с With чаще медленнее, чем с переменной, однако разброс в обе стороны минимальный и не стоит внимания…
Цитата
БМВ: пример был направлен больше на заметное отставание постоянного применения Range("a1")
полностью согласен - это наглядно. Я ещё добавил 5 копеек про Value2  ;)
«Тот, кто несет фонарь, спотыкается чаще, чем тот, кто идет следом.»
Иоганн Пауль Фридрих Рихтер
 
Цитата
Alec Perle написал:
ObjPtr
Ага, вот откуда ноги растут!) Проверил ещё для объектов, вложенных в Range, - результат аналогичный.

Всем большое спасибо!
Изменено: ControlAltExcel - 13 Дек 2019 10:07:24 (Цитата указала неверного автора сообщения)
 
Jack Famous, потому что лист один раз только указывать надо. В случае переименования листа (если отталкиваемся от имён листов) один раз только его указать надо. Следовательно вероятность совершить ошибку минимальная из-за "замыленного" глаза.
Знания и технологии принадлежат человечеству, и каждый сам решает делиться ими или исчезнуть вместе с ними.
 
Цитата
ocet p написал:
Сколько раз вы и другие (люди) писали Range("A1") без ".Value" при написании кода
всегда стараюсь указывать. И вот почему:
Код
Sub ValueOrNotValue()
    Range("A1:B2").Formula = "1"
    Range("A1:A2") = Range("A1:A2")
End Sub
посмотрите на значение ячеек A1:A2 до Range("A1:A2") = Range("A1:A2") и после :)
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Alemox написал: лист один раз только указывать надо
вместо двух — не такая уж колоссальная разница :D
впрочем, конечно же это вкусовщина  ;)
варианты
«Тот, кто несет фонарь, спотыкается чаще, чем тот, кто идет следом.»
Иоганн Пауль Фридрих Рихтер
Страницы: 1 2 След.
Читают тему (гостей: 1)
Наверх