Create deep copy of object [duplicate] - vb.net

This question already has answers here:
Deep cloning objects
(58 answers)
Closed 6 years ago.
I need help with the deep copying of objects in VB.net. I am aware of the fact that there is a great amount of topics dealing with that, but I was not able to adapt it to my problem. So hopefully someone can explain it to me using my code.
The problem: I have designed a class clsParameter which has one name, one unit, one value type and one value. The value can be a double or an object of type clsVectorParameter with the properties X,Y,Z. Now I want to do a deep copy of a parameter so that X,Y,Z are also copied.
Here are the two classes. The clone function below just represents a dummy. I know that it doesn't work like this but I didn't know a better way...
Public Class clsParameter
' Using the ICloneable interface
Implements ICloneable
' Variable definition
Private m_Name As String
Private m_Unit As String
Private m_Type As String
Private m_Value As Object
' Define set and get methods
Public Property Name As String
Get
Return m_Name
End Get
Set(ByVal value As String)
m_Name = value
End Set
End Property
Public Property Unit As String
Get
Return m_Unit
End Get
Set(ByVal value As String)
m_Unit = value
End Set
End Property
Public Property Value As Object
Get
Return m_Value
End Get
Set(ByVal value As Object)
m_Value = value
End Set
End Property
Public Property Type As String
Get
Return m_Type
End Get
Set(ByVal value As String)
m_Type = value
End Set
End Property
' Define constructor
Public Sub New(ByVal p_Name As String, ByVal p_Unit As String, ByVal p_Value As Object, ByVal p_Type As String)
m_Name = p_Name
m_Unit = p_Unit
m_Type = p_Type
m_Value = p_Value
End Sub
' Define Clone function to create independent copies of parameter instances
Public Function Clone() As Object Implements System.ICloneable.Clone
Dim cloneParam As New clsParameter(m_Name, m_Unit, m_Value, m_Type)
Return cloneParam
End Function
End Class
and the other class:
Public Class clsVectorParameter
Implements ICloneable
' Variable definition
Private m_x As Double
Private m_y As Double
Private m_z As Double
Public Property X As Double
Get
Return m_x
End Get
Set(ByVal value As Double)
m_x = value
End Set
End Property
Public Property Y As Double
Get
Return m_y
End Get
Set(ByVal value As Double)
m_y = value
End Set
End Property
Public Property Z As Double
Get
Return m_z
End Get
Set(ByVal value As Double)
m_z = value
End Set
End Property
' Define constructor
Public Sub New(ByVal p_x As Double, ByVal p_y As Double, ByVal p_z As Double)
m_x = p_x
m_y = p_y
m_z = p_z
End Sub
' Define Clone function to create independent copies
Public Function Clone() As Object Implements System.ICloneable.Clone
Dim cloneVecParam As New clsParameter(m_x, m_y, m_z, "Vec")
Return cloneVecParam
End Function
End Class
I use the class in this line:
Dim aNewParam As New clsParameter("Name", "Unit", New clsVectorParameter(x,y,z), "Type")
or
Dim aNewParam As New clsParameter("Name", "Unit", Double, "Type")
Later I need to create a deep copy of this aNewParam, so the x,y,z values are also independent for all parameters.
Thank you very much for your help!
Best regards,
Sebastian

Public Sub New(ByVal p_Name As String, ByVal p_Unit As String, ByVal p_Value As Object, ByVal p_Type As String)
m_Name = p_Name
m_Unit = p_Unit
m_Type = p_Type
If TypeOf (p_Value) Is Double Then
m_Value = p_Value
ElseIf TypeOf (p_Value) Is clsVectorParameter Then
m_Value = p_Value.Clone()
End If
End Sub

To keep your code in line with for example creating a clone of an XElement, do this from the constructor:
Dim obj1 = new clsVectorParameter(1, 1, 1)
Dim obj2 = new clsVectorParameter(obj1)
So now you only need to write an overloaded constructor, and there is no need for interfaces or seperate functions.
An overloaded constructor can be made like this: (you need to adapt this to your own class):
Public Class Foo
Dim x As Integer
Dim y As Integer
Dim z As Integer
Sub New(a As Integer, b As Integer, c As Integer)
x = a
y = b
z = c
End Sub
Sub New(old As Foo)
x = old.x
y = old.y
z = old.z
End Sub
End Class

Related

How do I construct an "Add" routine for a custom object list?

I feel really stupid asking this question, but here goes...
I'm trying to create a custom object in VB, that is itself a list (or collection, or "tuple" - I'm not sure what the difference between these is) of custom objects, and I need to create routines to add and remove these secondary objects to/from the larger custom object. So far, my code goes something like this:
Public Class parameterSet
Friend _xParameter As String
Public Property xParameter() As String
Get
Return _xParameter
End Get
Set(value As String)
_xParameter = value
End Set
End Property
Friend _yParameter As String
Public Property yParameter() As String
Get
Return _yParameter
End Get
Set(value As String)
_yParameter = value
End Set
End Property
Friend _zParameter As String
Public Property zParameter() As String
Get
Return _zParameter
End Get
Set(value As String)
_zParameter = value
End Set
End Property
Public Sub New(ByVal xParameter As String, ByVal yParameter As String, ByVal zParameter As String)
_xParameter = xParameter
_yParameter = yParameter
_zParameter = zParameter
End Sub
End Class
Public Class parameterCollection
Friend _parameterCollection As New List(Of parameterSet)
Friend Sub Add(xParameter As String, yParameter As String, zParameter As String)
Throw New NotImplementedException()
End Sub
End Class
What do I have to put in the Add routine to make this work?
Your first class ought to look like this:
Public Class ParameterSet
Public Property X As String
Public Property Y As String
Public Property Z As String
Public Sub New(x As String, y As String, z As String)
Me.X = x
Me.Y = y
Me.Z = z
End Sub
End Class
Your second class ought to look like this:
Imports System.Collections.ObjectModel
Public Class ParameterSetCollection
Inherits Collection(Of ParameterSet)
Public Overloads Sub Add(x As String, y As String, z As String)
Add(New ParameterSet(x, y, z))
End Sub
End Class
You might even want to do this:
Imports System.Collections.ObjectModel
Public Class ParameterSetCollection
Inherits Collection(Of ParameterSet)
Public Overloads Function Add(x As String, y As String, z As String) As ParameterSet
Dim item = New ParameterSet(x, y, z)
Add(item)
Return item
End Function
End Class
The Collection(Of T) class already provides all the standard collection functionality and you can extend it as required.

How to make Arrays of Object in VB.net?

I am unable to debug this.
Is my procedure of array-making wrong?
The error it shows is
System.NullReferenceException :'Object reference not set to an instance of an object'
Module Module1
Class Toy
Private Name, ID As String
Private Price As Single
Private MinimumAge As Integer
Dim Count As Integer
Public Sub New()
End Sub
Public Sub SetName(ByVal N As String)
Name = N
End Sub
Public Sub SetID(ByVal I As String)
'VALIDATION CHECK FOR ID !
While Len(I) < 4
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
End While
ID = I
End Sub
Public Sub SetPrice(ByVal SP As Single)
Price = SP
End Sub
Public Sub SetUserAge(ByVal SM As Integer)
'VALIDATION CHECK FOR AGE
While SM < 0 Or SM < 18
Console.WriteLine("Minimum age is 18")
End While
MinimumAge = SM
End Sub
Public Function GetName()
Return Name(Count)
End Function
Public Function GetID()
Return ID
End Function
Public Function GetPrice()
Return Price
End Function
Public Function GetAge()
Return MinimumAge
End Function
End Class
Class ComputerGame
Inherits Toy
Private Category, Consol As String
Public Sub New()
End Sub
Public Sub SetConsole(ByVal C As String)
While C <> "PS4" Or C <> "XBOX"
Console.WriteLine("Invalid console entered")
End While
Consol = C
End Sub
Public Sub SetCategory(ByVal SC As String)
Category = SC
End Sub
Public Function GetConsole()
Return Consol
End Function
Public Function GetCategory()
Return Category
End Function
End Class
Class Vehicle
Inherits Toy
Private Type As String
Private Length, Height, Weight As Single
Public Sub New()
End Sub
Public Sub SetType(ByVal TY As String)
While TY <> "Car" Or TY <> "Bus" Or TY <> "Truck"
Console.WriteLine("vehicle is not in list !")
End While
Type = TY
End Sub
Public Sub SetLength(ByVal SL As Single)
Length = SL
End Sub
Public Sub SetHeight(ByVal SH As Single)
Height = SH
End Sub
Public Sub SetWeight(ByVal SW As Integer)
Weight = SW
End Sub
Public Function GetT()
Return Type
End Function
Public Function GetLength()
Return Length
End Function
Public Function GetHeight()
Return Height
End Function
Public Function GetWeight()
Return Weight
End Function
End Class
Sub Main()
Dim ThisGame(6) As Toy
ThisGame(6) = New Toy
ThisGame(1).SetID("23456a")
ThisGame(2).SetID("236789b")
Console.WriteLine(ThisGame(1).GetID)
Console.ReadKey()
End Sub
End Module
This is what your Toy class should look like using the long method of Properties. Notice that you have Public Properties and a private field to store the values (sometimes called a backer field) Each Property has a Get and a Set procedure where you can add your validation code.
Public Class Toy
Private _Name As String
Public Property Name As String
Get
Return _Name
End Get
Set(value As String)
_Name = value
End Set
End Property
Private _ID As String
Public Property ID As String
Get
Return _ID
End Get
Set(value As String)
If value.Length < 4 Then
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
Exit Property
End If
_ID = value
End Set
End Property
Private _Price As Single
Public Property Price As Single
Get
Return _Price
End Get
Set(value As Single)
_Price = value
End Set
End Property
Private _MinimumAge As Integer
Public Property MinimumAge As Integer
Get
Return _MinimumAge
End Get
Set(value As Integer)
If value < 0 Or value < 18 Then
Console.WriteLine("Minimum age is 18")
Exit Property
End If
_MinimumAge = value
End Set
End Property
Private _Count As Integer
Public Property Count As Integer
Get
Return _Count
End Get
Set(value As Integer)
_Count = value
End Set
End Property
End Class
Current versions have Automatic Properties where the compiler provides the getter, setter, and backer fields. Notice that you can still write your own Get and Set where you need to add code.
Public Class Toy
Public Property Name As String
Public Property Price As Single
Public Property Count As Integer
Private _ID As String
Public Property ID As String
Get
Return _ID
End Get
Set(value As String)
If value.Length < 4 Then
Console.WriteLine("Kindly Enter the ID with Lenght of Max 4 Characters")
Exit Property
End If
_ID = value
End Set
End Property
Private _MinimumAge As Integer
Public Property MinimumAge As Integer
Get
Return _MinimumAge
End Get
Set(value As Integer)
If value < 0 Or value < 18 Then
Console.WriteLine("Minimum age is 18")
Exit Property
End If
_MinimumAge = value
End Set
End Property
End Class
Please read the in line comments in regards to your array.
Sub Main()
Dim ThisGame(6) As Toy 'You are defining and array with 7 elements of Toy
'Each element is Nothing at this point and you will get a null exception error if you
'try to access an element.
ThisGame(6) = New Toy 'Here you have created an instance of your class for the 7th element
'The other six elements are still nothing so the next 3 lines will get
'NullReferenceException: 'Object reference not set to an instance of an object.'
'ThisGame(1).ID = "23456a"
'ThisGame(2).ID = "236789b"
ThisGame(1) = New Toy
ThisGame(1).ID = "23456a"
ThisGame(2) = New Toy
ThisGame(2).ID = "236789b"
'Remember the first element in you array is ThisGame(0)
Console.WriteLine(ThisGame(1).ID)
Console.ReadKey()
End Sub

Class with a list of class in VB

I am trying to write a DLL that will accept an custom input with a nested list(of T)
I created 2 classes, a Main Class ClassPolyPoints and the nested Class classEF
I am getting an error when trying to pass the list(of classEF) object into the ClassPolyPoints object.
Dim TMP_effPoints As New List(Of classEF)
For i = 0 to 10
TMP_effPoints.Add(New classEff(
i,
i*0.125
))
Next
Dim tmpClass As New ClassPolyPoints(9.8765, TMP_effPoints)
Class that contains the nested list(of classEF)
Public Class ClassPolyPoints
Sub New(ByVal x_P0 As Double,
ByVal x_EffPoints As List(Of classEF))
_P0 = x_P0
With _effPoints
For Each a In x_EffPoints
.Add(New classEFF(
a.ID,
a.Eff
))
Next
End With
End Sub
Private _effPoints As List(Of classEff)
Public Property effPoints() As List(Of classEff)
Get
Return _effPoints
End Get
Set(ByVal value As List(Of classEff))
_effPoints = value
End Set
End Property
Private _P0 As Double
Public Property P0() As Double
Get
Return _P0
End Get
Set(ByVal value As Double)
_P0 = value
End Set
End Property
End Class
The nested class
Public Class classEF
Sub New(X_ID As Integer, X_Eff As Double)
_ID = X_ID
_Eff = X_Eff
End Sub
Private _ID As Integer
Public Property ID() As Integer
Get
Return _ID
End Get
Set(ByVal value As Integer)
_ID = value
End Set
End Property
Private _Eff As Double
Public Property Eff() As Double
Get
Return _Eff
End Get
Set(ByVal value As Double)
_Eff = value
End Set
End Property
End Class
You don't need to loop here just assign the list.
Public Class ClassPolyPoints
Sub New(ByVal x_P0 As Double,
ByVal x_EffPoints As List(Of classEF))
Me._P0 = x_P0
Me.effPoints = x_EffPoints
End Sub
'''
The issue is that you forgotten to create an istance of _effPoints before trying to add to the list new elements of class classEF:
That is in class ClassPolyPoints, you have to change the following declaration:
Private _effPoints As List(Of classEff)
into this:
Private _effPoints As New List(Of classEF)

InvalidOperationException on GetType

I try to serialize a Class in VB using XMLSerializer.
But when I call GetType for my Class I got a InvalidOperationException error.
Dim Playlist_serialize As New XmlSerializer(p.GetType)
Here is my class :
Public Class Playlist
Private p_name As String
Private p_elements As List(Of Playlist_element)
Sub New()
p_elements = New List(Of Playlist_element)
End Sub
Public Property Name() As String
Get
Name = p_name
End Get
Set(value As String)
p_name = value
End Set
End Property
Public Property Elements() As List(Of Playlist_element)
Get
Elements = p_elements
End Get
Set(value As List(Of Playlist_element))
p_elements = value
End Set
End Property
Here is my Playlist_element :
Public Class Playlist_element
Private p_Name As String
Private p_Type As String
Private p_Genre As String
Public Property Name() As String
Get
Name = p_Name
End Get
Set(value As String)
p_Name = value
End Set
End Property
Public Property Type() As String
Get
Type = p_Type
End Get
Set(value As String)
p_Type = value
End Set
End Property
Public Property Genre() As String
Get
Genre = p_Genre
End Get
Set(value As String)
p_Genre = value
End Set
End Property
Sub New(ByVal name As String, ByVal type As String, ByVal genre As String)
Me.Name = name
Me.Genre = genre
Me.Type = Type
End Sub
End Class
There are several issues with the way Playlist_element is coded. First your property getters are wrong. They need to return the backing field:
Public Property Name() As String
Get
' this does nothing:
'Name = p_Name
Return p_Name
End Get
Set(value As String)
p_Name = value
End Set
End Property
Next, I would not use Type as a property name even if you can. If you drill into the inner exception and view the message, it tells you that it cannot serialize PlayList_element because it does not have a simple constructor. All serializers require this because they do not know how to use:
Sub New(ByVal name As String, ByVal type As String, ByVal genre As String)
p_Name = name
p_Genre = genre
p_Type = type
End Sub
' add:
Public Sub New()
End Sub
It should work fine. I should note that as of VS2010, you can use auto-implemented properties and skip a lot of that code:
Public Class Element
Public Property Name() As String
Public Property Type() As String
Public Property Genre() As String
Sub New(name As String, type As String, genre As String)
_Name = name
_Genre = genre
_Type = type
End Sub
Public Sub New()
End Sub
End Class
VS provides a "hidden" backing field as with _Name, _Genre etc.

Declare and and define Property in VB

I have two Class and I want to save my data into arrays form text box like this:
Students.Name(txtID.Text-1).MathMark = txtMark.Text
but I get error: Object reference not set to an instance of an object
my code is:
Dim StudentsNumber as Integer = txtstdnum.Text
Dim Students as New StudentsInf(StudentsNumber)
Students.Name(txtID.Text-1).MathMark = txtMark.Text
Public Class StudentsInf
Private mName() As String
Sub New(ByVal StudentNumbers As Integer)
ReDim mName(StudentNumbers-1)
End Sub
Public Property Name(ByVal Index As Integer) As LessonsMark
Get
Return mName(Index)
End Get
Set(ByVal Value As LessonsMark)
mName(Index) = Value
End Set
End Property
End Class
Public Class LessonsMark
Private mMathMark() As Object
Public Property MathMark() As Object
Get
Return mMathMark
End Get
Set(ByVal Value As Object)
mMathMark = Value
End Set
End Property
End Class
This:
Private mName() As String
needs to be:
Private mName() As LessonsMark
then you have to create the objects in your constructor, something like:
Sub New(ByVal StudentNumbers As Integer)
ReDim mName(StudentNumbers - 1)
For i As Integer = 0 To StudentNumbers - 1
mName(i) = New LessonsMark()
Next
End Sub
then it looks like your LessonsMark class is declaring an array of objects when it looks like it should be just a string property:
Public Class LessonsMark
Private mMathMark As String
Public Property MathMark As String
Get
Return mMathMark
End Get
Set(ByVal Value As String)
mMathMark = Value
End Set
End Property
End Class