Ссылка NullReferenceException или Object, не установленная на экземпляр объекта, возникает, когда объект класса, который вы пытаетесь использовать, не создается. Например:
Предположим, что у вас есть класс с именем Student.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Теперь рассмотрим другой класс, в котором вы пытаетесь получить полное имя учащегося.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Как видно из вышеприведенного кода, оператор Student s - объявляет только переменную типа Student, обратите внимание, что класс Student не создается в этой точке. Следовательно, когда выполняется выполнение инструкции s.GetFullName (), она выкинет исключение NullReferenceException.
Как и многие современные языки, VB6 имеет типы значений и ссылочные типы. Классы определяют ссылочные типы. С другой стороны, ваши основные типы, такие как Integer
, являются типами значений.
Основное различие заключается в назначении:
Dim a as Integer
Dim b as Integer
a = 2
b = a
a = 1
В результате a
равно 1 и b
равно 2. Это потому, что присваивание в типах значений делает копию. Это потому, что каждая переменная имеет пространство, выделенное для значения в стеке (в случае VB6, Integer занимает 2 байта в стеке).
Для классов это работает иначе:
Dim a as MyClass
Dim b as MyClass
Set a = New MyClass
a.Value1 = 2
Set b = a
a.Value1 = 1
В результате обе a.Value1
и b.Value1
равны 1. Это потому, что состояние объекта хранится в куче, а не в стеке. В стек хранится только ссылка , поэтому Set b = a
перезаписывает ссылку. Интересно, что VB6 явно говорит об этом, заставляя использовать ключевое слово Set
. Большинство других современных языков этого не требуют.
Теперь вы можете создавать свои собственные типы значений (в VB6 они называются User Defined Types, но на большинстве других языков они называются структурами или структурами) , Вот учебник .
Различия между классом и определенным пользователем типом (кроме класса, являющегося ссылочным типом и UDT, являющегося типом значения) состоит в том, что класс может содержат методы (методы и свойства), в которых UDT не может. Если вы просто ищете класс типа записи, тогда может быть вашим решением UDT.
Вы можете использовать сочетание этих методов. Предположим, вам нужен класс, потому что у вас есть определенные поведения и вычисления, которые вы хотите включить вместе с данными. Вы можете использовать шаблон memento , чтобы удерживать состояние объекта внутри UDT:
Type MyMemento
Value1 As Integer
Value2 As String
End Type
В своем классе убедитесь, что все ваше внутреннее состояние хранится внутри частного члена типа MyMemento
. Напишите свои свойства и методы, чтобы они использовали данные только в одной переменной частного члена.
Теперь сделать копию вашего объекта просто. Просто напишите новый метод в своем классе под названием Copy()
, который возвращает новый экземпляр вашего класса и инициализирует его копией собственного memento:
Private Memento As MyMemento
Friend Sub SetMemento(NewMemento As MyMemento)
Memento = NewMemento
End Sub
Public Function Copy() as MyClass
Dim Result as MyClass
Set Result = new MyClass
Call Result.SetMemento(Memento)
Set Copy = Result
End Function
Friend
только скрывает его от материала вне вашего проекта, поэтому он мало чем скрывает SetMemento
, но это все, что вы можете сделать с VB6.
HTH
или мне нужно скопировать объект по одному члену за раз ...
blockquote>К сожалению, да.
Возможно (но технически очень very сложно) написать COM-сервер на C ++, который, используя интерфейс IDispatch, скопирует значение каждого свойства, но на самом деле это Программирование в высоком храме , если бы мне пришлось это сделать, я не знаю, мог ли я сделать это, но я бы посмотрел на что-то вроде 10-дневной работы ( и я знаю, как COM реализован на C ++, мне также необходимо исследовать, есть ли в ATL-инфраструктуре что-нибудь, чтобы помочь и т. д.).
Я работал с Vb3, 4,5 и amp; 6 для чего-то вроде 10 лет (руки, 5 дней в неделю) и никогда не находили хорошего способа сделать это, помимо ручного внедрения шаблонов сериализации, таких как Mementos и Save & amp; Магазин, который действительно просто сводился к фантастическим способам копирования каждого участника, по одному за раз.
@Scott Whitlock, я не смог заставить ваш код работать, но если он будет работать, это было бы здорово.
Я создал регулярный модуль, в который я помещал тип memment
Type MyMemento
Value1 As Integer
Value2 As String
End Type
Затем я создаю модуль класса MyClass с кодом
Private Memento As MyMemento
Friend Sub SetMemento(NewMemento As MyMemento)
Memento = NewMemento
End Sub
Public Function Copy() as MyClass
Dim Result as MyClass
Set Result = new MyClass
Result.SetMemento(Memento)
Set Copy = Result
End Function
Наконец, я пытаюсь вызвать функцию копирования в другом регулярном модуле, таком как
Sub Pruebas()
Dim Primero As MyClass, segundo As MyClass
Set Primero = New MyClass
Set segundo = New MyClass
Set segundo = Primero.Copy
End Sub
Я получаю сообщение (под рисунком): Ошибка компиляции: El tipo de agumento de ByRef не совпадает
Вот изображение (не более 10 баллов, так вот ссылка): http: //i.stack.imgur.com/KPdBR.gif
Я не смог получить сообщение на английском языке, я живу в Испании.
Не могли бы вы так любезно предоставить пример в VBA Excel ?, я действительно пытался сделать эту работу.
Спасибо за вашу работу
========== ==============================================================================================================================================
Проблема была в строке «Result.SetMemento (Memento)», в VBA ее нужно было вызвать с помощью «Call»
Public Function Copy() As MyClass
Dim Result As MyClass
Set Result = New MyClass
Call Result.SetMemento(Memento)
Set Copy = Result
End Function
Это отлично работает, спасибо Скотту Уитлоку, ты гений