По какой причине не создается экземпляр объекта во время объявления?

#vb6

#vb6

Вопрос:

Недавно мне пришлось покопаться в коде VB6, и я повсюду видел этот шаблон:

 dim o as obj
set o = new obj
  

Почему бы и нет?

 dim o as new obj
  

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

Комментарии:

1. Хм, интересно, я кодировал на VB6 в течение 3 лет, и что я помню, так это то, что эти два варианта совершенно верны.

2. dim o as new obj создается при первом доступе, не раньше. Таким образом, каждый вызов свойства / метода для него сопряжен с накладными расходами на проверку переменной на Nothing .

3. @wqw Каждое свойство имеет накладные расходы на проверку отсутствия ничего даже после создания экземпляра объекта или только в первый раз?

4. @AngryHacker Да, потому что вы вообще не можете получить доступ к свойствам объекта, если только объект не является «Not Nothing». Таким образом, каждый доступ подразумевает «Если obj ничего не значит, тогда установите obj = New myObj» перед ним.

5. @wqw давайте не будем забывать, что после использования в цикле метод «New obj» не уничтожит и не воссоздаст объект заново, однако, если вы делаете «Dim o как obj» и «Set o = New obj», то каждый раз, когда выполняется эта последовательность, она уничтожает и воссоздает переменную «o». Особенно, если объект является типом коллекции, и он не уничтожается и не создается заново (как это было бы при выполнении только «Dim o как новая коллекция»), каждый раз, когда вы добавляете элементы в коллекцию («o» в данном случае, когда в цикле), он будет просто продолжать повторно добавлять элементы в коллекцию, и у вас будут устаревшие данные из предыдущего цикла, большая разница. Смотрите мой ответ.

Ответ №1:

Могут быть и другие причины, но в VB6 использование ключевого слова New при затемнении объекта может привести к неожиданным результатам, потому что VB будет создавать экземпляр объекта всякий раз, когда на него ссылаются.

 Dim objMyObject as New SomeObject

Set objMyObject = Nothing   ' the object is nothing

If objMyObject Is Nothing Then  ' referencing the object instantiates again
   MsgBox "My object is destroyed"  ' what you would probably expect
Else
   MsgBox "My object still exists"
End If
  

Комментарии:

1. Именно по этой причине.

2. Этот ответ движется в правильном направлении, но, возможно, не лучшая формулировка? Я бы не использовал непредсказуемый . Результаты полностью предсказуемы , но часто неожиданны для большинства разработчиков. Результаты также могут означать, что ошибки программирования вызывают слегка неправильное поведение во время выполнения, а не приятное простое исключение «Переменная объекта не установлена»

3. @MarkJ Вы высказали отличную мысль, и я соответствующим образом отредактировал ответ

Ответ №2:

Этот вопрос затрагивает одну из многих причин, по которым опытным программистам действительно не нравится VB6. New Ключевое слово изменяет способ работы объявленной переменной. Например:

 Dim MyObject As MyClass
Set MyObject = New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()
  

… выдает исключение во время выполнения, в то время как это:

 Dim MyObject As New MyClass
Set MyObject = Nothing
Call MyObject.MyMethod()
  

… не создает. Лично я, если я попытаюсь установить переменную в Nothing , то повторное обращение к ней почти наверняка будет ошибкой, и мне бы очень хотелось, чтобы программа завершила работу с ошибкой, большое вам спасибо. Это особенно важно в случае, когда класс выделяет ресурсы в инициализаторе (конструкторе) и ему необходимо избавиться от них в деструкторе. Достаточно легко написать код, который неправильно ссылается на переменную, установленную на Nothing , возможно, когда вы хотите проверить результирующее значение или что-то в этом роде. Выполнение этого может привести к повторному созданию экземпляра класса с захватом всех ненужных ресурсов.

Причина такого странного поведения заключается в том, что формы VB6 (которые являются классами) работают так, как новичок ожидал бы от них работы. Существует неявно объявленная глобальная переменная с тем же именем и типом, что и у каждой определенной формы, поэтому:

 Call frmMain.Show
  

… не происходит сбой. Это то же самое поведение. Это действительно делает:

 If frmMain Is Nothing Then
    Set frmMain = New frmMain
End If
Call frmMain.Show
  

Это очень сильно противоречит тому, к чему мы привыкли в других объектно-ориентированных языках, так что, на мой взгляд, это плохая идея. Он пытается скрыть тот факт, что MyObject является ссылочным типом, и все же, когда вы пишете что-то подобное (без использования Set ):

 MyObject = New MyClass
  

… тогда вы получаете исключение времени выполнения вместо ошибки компилятора, потому что вы не использовали Set команду. Компилятор знает, что это ссылочный тип… почему я должен использовать Set , и даже если я это сделаю, почему бы не рассказать мне об этом раньше?

В любом случае, отвечая на ваш вопрос, вам редко требуется поведение, подразумеваемое использованием Dim ... New синтаксиса, потому что вы хотите контролировать создание и уничтожение объектов. Фактически, единственный раз, когда это когда-либо имело бы смысл, — это при создании глобальных одноэлементных объектов (таких frmMain как выше), где вам просто нужен синтаксический сахар. Я бы сказал, что глобальные синглтоны в любом случае плохая идея, поэтому, если бы я мог отключить возможность использования Dim ... New синтаксиса, я бы это сделал.

Комментарии:

1. Из всех многих веских причин, по которым vb6 не нравится, я бы сказал, что эту едва ли стоит даже упоминать, ха-ха

2. @Mat’Smug достаточно справедлив в отношении IDE, но подобные атрибуты по существу невидимы для программистов VB6. На самом деле, они вообще где-нибудь документированы?

Ответ №3:

Вот еще одно предостережение:

 For x = 1 to 100
   dim obj as new MyObject

   'Do something with obj
Next
  

Можно ожидать, что новый объект создается 100 раз, но вы обнаружите, что он создается только в самый первый раз. Это давно застало меня врасплох.

Хотя я все еще постоянно использую эту нотацию. Просто убедитесь, что вы знаете поведение.

Комментарии:

1. это тоже сбило меня с толку

2. Частично проблема здесь действительно заключается в неправильном использовании, Dim поскольку MyObject область действия всегда будет на уровне процедуры, а не на уровне цикла. Поэтому размещение его внутри цикла for вводит в заблуждение.

Ответ №4:

Я хотел добавить к ответу Брэндона Мура…

Итак, продолжаем цикл…

 For x = 1 to 100
  Dim obj as New Collection
  obj.Add "New String Number " amp; x
Next x
  

Даже если вы добавили, скажем, 20 элементов в obj при x = 1, при x = 2 все эти 20 элементов все равно будут там! в то время как, если бы вы установили obj= new MyObject, то этого бы не было! Это самая важная причина, поскольку однажды я попался на этом в большой области цикла в моем коде, материал добавлялся по всей программе, и я понятия не имел почему, ничего не удалялось или сбрасывалось.

Итак, если вместо:

   Dim obj as New Collection
  

Вы написали файл, содержащий:

   Dim obj as Collection
  Set obj = New Collection
  

Тогда у вас была бы коллекция obj, сбрасываемая каждый раз, что, вероятно, вам и нужно, но если вы хотите, чтобы она была установлена только один раз, тогда используйте метод As New Collection . Но, если бы вы просто хотели установить его один раз, вы, вероятно, поместили бы его вне цикла.

Кроме того, если вы не работаете в цикле, но переменная (Collection) определена в статической функции или определена с помощью ключевого слова static, применяется то же самое, не запуск Set obj = New Collection гарантирует, что у вас будут устаревшие данные с вашего последнего использования obj / Collection, что может быть очень плохо.

Итак, в заключение, два метода на самом деле очень разные (и могут иметь разное поведение)!