Classes and arrays how to initialize? - vb.net

I’m working on some partial classes but I can’t figure out how to do it.
This is my classes:
Partial Public Class Form
Private InfoField() As Info
Private FormgroupField() As FormGroup
Private tittle As String
Public Property Info() As Info()
Get
Return Me. InfoField
End Get
Set
Me. InfoField = value
End Set
End Property
Public Property FormGroup() As FormGroup()
Get
Return Me.GromGroupField
End Get
Set
Me.FormGroupField = value
End Set
End Property
Public Property tittle() As String
Get
Return Me.tittleField
End Get
Set
Me.tittleField = value
End Set
End Property
End class
Partial Public Class Info
Private ChangeFormField() As ChangeForm
Private formYearField() As FormYea
Private idField As String
Public Property ChangeForm() As ChangeForm()
Get
Return Me.changeFormField
End Get
Set
Me.changeFormField = value
End Set
End Property
Public Property FormYear() As FormYear()
Get
Return Me.formYearField
End Get
Set
Me.formYearField = value
End Set
End Property
Public Property id() As String
Get
Return Me.idField
End Get
Set
Me.idField = value
End Set
End Property
End Class
Partial Public Class ChangeForm
Private idField As String
Private valueField As String
<properties goes here>
End Class
Partial Public Class FormYear
Private idField As String
Private valueField As String
<properties goes here>
End Class
And for the class FormGroup the organization is the same.
I want to build partial classes to extend these classes, so when I use all this classes in another project I only have to deal with (see) the topmost class (Form) and not the other classes (like Info and FormGroup. This is what I like to do:
Partial Public Class Form
Public Sub Init()
Me.Info = New Info
Me.FormGroup = New FormGroup
Me.Info.Init()
Me.FormGroup.Init()
End Sub
End Class
Partial Public Class Info
Public Sub Init()
Me.FormYear = New FormYear
Me.ChangeForm = New ChangeForm
Me.changeForm.Init()
End Sub
But I can’t write
Me.Info = New Info
Me.FormGroup = New FormGroup
because it is arrays with classes. How can I do it in my Form and Info class?
Thanks in advance.

You must first create an array, then loop over the array and assign each element. Also, unless you have a good, strong reason, do this in the constructor rather than a separate init method.
Public Class Form
Public Sub New()
'In VB, you give the max index, not the length.
'I prefer listing this as (whatever I want for length) - 1
Me.Info = New Info(size - 1) {}
For i = 0 to size - 1
Me.Info(i) = New Info()
Next
'similarly for other fields
End Sub
End Class
Alternatively, if you find yourself with a lot of array fields, and they all have default constructors, you could create a FixedCollection class that would encapsulate the repetitive initialization code.
Public Class FixedCollection(Of T As New)
Inherits Collection(Of T)
Public Sub New(ByVal size As Integer)
MyBase.New(New T(size - 1) {})
For i = 0 to size - 1
Me.Items(i) = New T()
Next
End Sub
'alternate constructors if you need additional initialization
'beyond construction of each element
Public Sub New(ByVal size As Integer, ByVal creator As Func(Of T))
MyBase.New(New T(size - 1) {})
If creator Is Nothing Then Throw New ArgumentNullException("creator")
For i = 0 to size - 1
Me.Items(i) = creator()
Next
End Sub
'this overload allows you to include the index in the collection
'if it would matter to creation
Public Sub New(ByVal size As Integer, ByVal creator As Func(Of Integer, T))
MyBase.New(New T(size - 1) {})
If creator Is Nothing Then Throw New ArgumentNullException("creator")
For i = 0 to size - 1
Me.Items(i) = creator(i)
Next
End Sub
'other collection overrides as needed here
End Class
EDIT: Added constructor overloads for when an element constructor is not enough.
If you only use the constructors with a creator parameter, you could remove the New constraint on T.
Use the overloads as follows:
Public Class Form
Private InfoField As New FixedCollection(Of Info)(10,
Function()
Dim ret As New Info()
ret.Init()
End Function)
End Class
Based on your comments, it seems like the Init methods are an unfortunate necessity. If possible, I would recommend that you find a way to get the generated constructor changed to call this method (defined in the generated code using partial methods) for you rather than forcing you to call it yourself.

You can initialize an Array of a Class like this:
Public FieldTypes As FieldTypeInfo() =
{
New FieldTypeInfo("Byte", 1),
New FieldTypeInfo("Int16", 2),
New FieldTypeInfo("Int32", 3),
New FieldTypeInfo("Integer", 3),
New FieldTypeInfo("Int64", 4),
New FieldTypeInfo("UInt16", 5),
New FieldTypeInfo("UInt32", 6),
New FieldTypeInfo("UInteger", 6),
New FieldTypeInfo("UInt64", 7)
}

Related

Collection class of specific type containing basic features

Every time i use some class e.g Artikel as follows:
Public Class Artikel
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer
End Class
For such classes i would like to have collection class. The features i would like to have is like:
--> Add (passing Artikel object)
--> Remove (passing Artikel object)
--> Sort entire collection (based on Position property desc/asc)
--> Compare two Artikels (pass by Artikels and tell by which property has to be compared)
--> Check whether two artikels equals
--> Every added artikel has to be marked by Key (so maybe dictionary)? <key><Artikel>
--> Remove Artikel (passing by Key index)
Could somone from you there tell me or even better provide example of collection class pass those requirments?
EDIT: Startup:
Artikel's collection:
Option Strict On
Public Class Articles
Public Property collection As Dictionary(Of Integer, Artikel)
Sub New()
'Initiate new collection
collection = New Dictionary(Of Integer, Artikel)
End Sub
'Add new Artikel to collection
Public Function AddToCollection(ByVal artikel As Artikel) As Boolean
collection.Add(artikel)
Return True
End Function
'Remove specific Artikel
Public Sub RemoveFromCollectionByArtikel(artikel As Artikel)
If Not IsNothing(collection) Then
collection.Remove(artikel)
End If
End Sub
'Get collection
Public Function GetCollection() As Dictionary(Of Integer, Artikel)
Return collection
End Function
'Sort collection by property position
Public Sub SortByPosition()
collection.Sort()
End Sub
'Remove specific sending keys and then reorder them
Public Sub RemoveAllMarkedAsDeleted(keys As List(Of Integer))
'-- Check whther anything has been marked as deleted
If keys.Count > 0 Then
For Each row In keys
collection.Remove(row)
Next
ReorderKeys()
End If
'Reorder all Artikels in collection
Private Sub ReorderKeys()
Dim newCollection As New Dictionary(Of Integer, Artikel)
Dim index As Integer = 0
For Each collitem In collection
newCollection.Add(index, collitem.Value)
index += 1
Next
collection.Clear()
collection = newCollection
End Sub
End Class
Artikel class (additionally i implemented IComparable to be able to sort)
Option Strict On
Public Class Artikel
Implements IComparable(Of Artikel)
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer
Public Function CompareTo(pother As Artikel) As Integer Implements IComparable(Of Artikel).CompareTo 'we can sort because of this
Return String.Compare(Me.Position, pother.Position)
End Function
Public Shared Function FindPredicate(ByVal partikel As Artikel) As Predicate(Of Artikel)
Return Function(partikel2 As Artikel) partikel.ID = partikel2.ID
End Function
Public Shared Function FindPredicateByUserId(ByVal partikel As String) As Predicate(Of Artikel)
Return Function(partikel2 As Artikel) partikel = partikel2.ID
End Function
End Class
Parts of it look good, but I would ultimately do it a bit differently. First, consider overloads on the item class to make them easier to create and default initialization:
Public Class Article
Property ID As Integer = -1
Property Key As String = ""
Property Name As String = ""
Property Position As Integer = -1
Property PubDate As DateTime = DateTime.Minimum
Public Sub New()
End Sub
' whatever minimum data a new item requires
Public Sub New(k As String, n As String)
Key = k
Name = n
End Sub
' full initialization:
Public Sub New(k As String, n As String, pos As Int32,
pubDt As DateTime)
...
End Sub
End Class
I added some properties for variety, and I suspect "Nummer" might be the "Key" mentioned in the OP, but whatever it is, I would add it to the Article class as that name, if it has some importance.
You might need a simple ctor for serialization (???). Some of these will find and use a Private parameterless constructor, but your code will be forced to use one of the overloads in order to provide some minimum level of data when a new one is created.
You probably do not need IComparable. That is typically for more complex comparisons, such as multiple or complex properties. An example is a carton or box:
If (width = Other.Width) AndAlso (height = Other.Height) Then
Return 0
ElseIf (width = Other.Height) AndAlso (height = Other.Width) Then
Return 0
End If
Plus more gyrations to work out which is "less" than the other. One reason you dont need it, is because If Art1.Postion > Art2.Postion is trivial. The other reason in your case, is because a Dictionary cannot be sorted.
Rather than a Dictionary, an internal List would work better for some of the things you describe but still allow you to have it act like a Dictionary to the extent you need it to. For this, I might build it using ICollection<T>:
Public Class ArticleCollection
Implements ICollection(Of Article)
Pressing Enter after that line will add all the required methods including:
Public Sub Add(item As Article) Implements ICollection(Of Article).Add
Public Sub Clear() Implements ICollection(Of Article).Clear
Public Function Contains(item As Article) As Boolean Implements ICollection(Of Article).Contains
Public ReadOnly Property Count As Integer Implements ICollection(Of Article).Count
Public Function Remove(item As Article) As Boolean Implements ICollection(Of Article).Remove
It remains completely up to you how these are implemented. It also doesn't rule out adding methods such as RemoveAt(int32) or RemoveByKey(string) depending on what you need/how it will be used. One of the benefits to ICollection(Of T) is that it includes IEnumerable which will allow use for each loops (once you write the Enumerator): For Each art In Articles
To emulate a dictionary to allow only one item with a specific property value:
Public Class ArticleCollection
Implements ICollection(Of Article)
Private mcol As List(Of Article)
...
Public Sub Add(item As Article) Implements ICollection(Of Article).Add
' check for existing key
If KeyExists(item.Key) = False Then
mcol.Add(item)
End If
End Sub
You can also overload them:
' overload to match Article ctor overload
Public Sub Add(key As String, name As String)
If KeyExists(key) = False Then
' let collection create the new item
' with the minimum required info
mcol.Add(New Article(key, name))
End If
End Sub
If you add an Item Property, you can index the collection ( Articles(3) ):
Property Item(ndx As Int32) As Article
Get
If ndx > 0 AndAlso ndx < mcol.Count Then
Return mcol(ndx)
Else
Return Nothing
End If
End Get
Set(value As Article)
If ndx > 0 AndAlso ndx < mcol.Count Then
mcol(ndx) = value
End If
End Set
End Property
' overload for item by key:
Public Property Item(key As String) As Article
An Add method and an Item Property will be important if the collection will display in the standard NET CollectionEditor.
There are several ways to implement sorting. The easiest is to use linq in the code which uses your collection:
Articles = New ArticleCollection
' add Article items
Dim ArticlesByDate = Articles.OrderBy(Function(s) s.PubDate).ToList()
Where PubDate is one of the Article properties I added. The other way to handle sorting is by the collection class returning a new collection (but it is so simple to do, there is little need for it):
Friend Function GetSortedList(bSortAsc As Boolean) As List(Of Article)
If bSortAsc Then
Return mcol.OrderBy(Function(q) q.PubDate).
ThenBy(Function(j) j.Position).ToList()
Else
Return mcol.OrderByDescending(Function(q) q.PubDate).
ThenByDescending(Function(j) j.Position).ToList()
End If
End Function
Whether it implements ICollection(Of T), inherits from ICollection(Of T) or does work off a Dictionary depends entirely on what this is, how it is used and whatever rules and restrictions there are (including if it will be serialized and how). These are not things we know.
MSDN has an article on Guidelines for Collections which is excellent.
Create your class
Public Class Artikel
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer
sub new (_ID as integer, _Nummer as string, _Name as string, _Position as integer)
ID = _ID
Nummer = _Nummer
Name = _Name
Position = _Position
End Sub
End Class
Create another class which holds a private list and add sub routines to it
Public Class ArtikelList
Private _List as new list (of Artikel)
Public sub remove(Key as integer)
Dim obj as Artikel = nothing
for each x as Artikel in _List
if x.ID = Key then
obj = x
exit for
end if
Next
if not isnothing(obj) then
_List.remove(obj)
end if
End sub
Sub Add(obj as Artikel)
Dim alreadyDeclared as boolean = falsse
for each x as Artikel in _List
if x.ID = obj.id then
alreadyDeclared = true
exit for
end if
Next
if not AlreadyDeclared then
_List.add(obj)
Else
'Somehow inform the user of the duplication if need be.
end if
End sub
End Class
Then use your list class.
dim L as new ArtikelList
L.add(new Artikel(1280, "AFKforever!", "Prof.FluffyButton", 96))
L.remove(1280)
I only added one sub routine as an example. I hope it helps but feel free to ask for more example routines.
This can also be done by creating a class which inherits from the list class, exposing all list class functionality but by using this method you are forced to create every subroutine that will be used. This way you only use routines that you created exclusively for the purpose Artikel objects handling.
Check if two Artikels are equal
Public Class Artikel
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer
sub new (_ID as integer, _Nummer as string, _Name as string, _Position as integer)
ID = _ID
Nummer = _Nummer
Name = _Name
Position = _Position
End Sub
End Class
Public Overrides Overloads Function Equals(obj As Object) As Boolean
If obj Is Nothing OrElse Not Me.GetType() Is obj.GetType() Then
Return False
else
dim _obj as artikel = obj
if Me.ID = _obj.ID then
Return true
else Return False
End If
End Function
End Class
Use it like:
If x.equals(y) then
'they have the same ID
end if

Need Help Initializing a Generic Property in VB.Net

I've created a request class. Here is an abbreviated version of it:
Public Class Request(Of T)
Private _Account As String
Public Property Account() As String
Get
Return _Account
End Get
Set(ByVal value As String)
_Account = value
End Set
End Property
Private _InnerRequest As T
Public Property InnerRequest() As T
Get
Return Me._InnerRequest
End Get
Set(ByVal value As T)
Me._InnerRequest = value
End Set
End Property
End Class
And then I have two other classes that I intend to use with this one - again, abbreviated
Public Class Individual
Public FirstName As String
Public LastName As String
Friend Sub New()
End Sub
End Class
And
Public Class Commercial
Public EntityName As String
Friend Sub New()
End Sub
End Class
Again, both of these are pretty abbreviated. The issue comes in when I attempt to use the properties of individual or commercial:
Dim Req As New Request(Of Individual)()
Req.InnerRequest.FirstName = "Herman" <-- Null Ref Exception
So... how do I get my inner request null ref exception kicked? I tried simply using Me._InnerRequest = New T in the New sub of Request, but no dice. Is there a way to handle this?
Req.InnerRequest must be set to an object instance of Individual first.
Req.InnerRequest = new Individual()
Req.InnerRequest.FirstName = "Herman"
Or create an instance for InnerRequest with the following modifications
Public Class Request(Of T As {New}) 'Classes of type T must have a public new constructor defined
::
Private _InnerRequest As New T() 'Creates a new class of type T when an instance is created of Request
And make the constructors of the other classes Public instead of Friend.
Than you can directly do
Dim Req As New Request(Of Individual)()
Req.InnerRequest.FirstName = "Herman"
#Barry already answered what the main problem is, but here's an alternate syntax if you prefer object initializers:
Req.InnerRequest = new Individual() With { FirstName = "Herman" }
Or, if you prefer, you could overload the constructor for your Individual class:
Dim individual As New Individual("Herman")
Req.InnerRequest = individual
With the Individual class looking like:
Public Class Individual
Public FirstName As String
Public LastName As String
Friend Sub New()
End Sub
Friend Sub New(firstName As String)
Me.FirstName = firstName
End Sub
End Class
You probably should consider restricting the T to some Entity class:
Public Class Request(Of T As Entity)
From which both Individual and Commercial will inherit:
Public Class Individual : Inherits Entity
Then maybe declare an overridable property Name of type String on this Entity class (which can be abstract/MustInherit), this should provide some flexibility. Otherwise you'd be having a hard time consuming your design pattern.

VB.Net check for duplicate items in a collection base

I have a class that inherits from CollectionBase. I tried to use the contains method to detect whether the Key already exists before inserting a new one. Here is what I have tried.
<Serializable()> Public Class validationList
Inherits CollectionBase
Public Function Add(ByVal Item As validationItem) As Integer
Return Me.List.Add(Item)
End Function
Default Public ReadOnly Property Item(ByVal index As Integer) As validationItem
Get
Return CType(List.Item(index), validationItem)
End Get
End Property
Public Sub Remove(ByVal index As Integer)
Me.List.RemoveAt(index)
End Sub
Protected Overrides Sub OnInsert(ByVal index As Integer, ByVal value As Object)
If Me.List.Contains(value) Then MsgBox("Already exist")
MyBase.OnInsert(index, value)
End Sub
Public Function IndexOf(ByVal key As validationItem)
Return List.IndexOf(key)
End Function
Public Sub AddRange(ByVal item() As validationItem)
For counter As Integer = 0 To item.GetLength(0) - 1
List.Add(item(counter))
Next
End Sub
End Class
<Serializable()> Public Class validationItem
Implements IEquatable(Of validationItem)
Private _key As validationTypes
Private _value As String
Public Sub New()
' Empty constructor is needed for serialization
End Sub
Public Sub New(ByVal k As validationTypes, ByVal v As String)
_key = k
_value = v
End Sub
Public Enum validationTypes
Madatory = 0
[Integer] = 1
Numeric = 2
[Decimal] = 3
MaxValue = 4
MinValue = 5
MinLength = 6
Email = 7
End Enum
Public Property Value As String
Get
Return _value
End Get
Set(ByVal Value As String)
_value = Value
End Set
End Property
Public Property Key As validationTypes
Get
Return _key
End Get
Set(ByVal value As validationTypes)
_key = value
End Set
End Property
Protected Overloads Function Equals(ByVal eqItem As validationItem) As Boolean Implements IEquatable(Of Testing_Project.validationItem).Equals
If eqItem Is Nothing Then Return False
Return Me._key = eqItem.Key
End Function
Public Overrides Function Equals(ByVal eqItem As Object) As Boolean
If eqItem Is Nothing Then Return False
Dim eqItemObj As validationItem = TryCast(eqItem, validationItem)
If eqItemObj Is Nothing Then Return False
Return Equals(eqItemObj)
End Function
Public Overrides Function GetHashCode() As Integer
Return Me._key.GetHashCode()
End Function
End Class
The validationList will be exposed from a usercontrol as a property, so that items could be added from the designer. When adding items I need to detect whether they already exist. I tried overriding the OnInsert but this sometime return that duplicates exists even when their aren't and doesn't report that duplicate exist when I try to add existing keys.
This indirectly answers the question after dealing with the issue which emerged in comments about Collection(Of T):
Add a reference to System.Collections.ObjectModel if needed, then
Imports System.Collections.ObjectModel
' a ValidationItem collection class
Public Class ValidationItems
Inherits Collection(Of ValidationItem)
Public Shadows Sub Add(NewItem As ValidationItem)
' test for existence
' do not add if it is not unique
Dim dupe As Boolean = False
For n As Int32 = 0 To Items.Count - 1
If Items(n).Key = NewItem.Key Then
dupe = True
Exit For
End If
Next
If dupe = False then
items.Add(newitem)
End if
' I would actually use an IndexOfKey function which might
' be useful elsewhere and only add if the return is -1
If IndexOfKey(NewItem.Key) <> -1 Then
Items.Add(newItem)
End If
End Sub
Some NET collection types implement Add as a function and return the item added. This sounds weird since you pass it the item to add. But returning Nothing if the item cannot be added is a neat semaphore for "I cant/wont do that". I cant recall if the std NET Collection Editor recognizes that or not.
One problem with using Contains is that it will test if item passed as param is the same object as one in the list. They never will be the same object, even if they have the same values. Testing the key in a loop is simpler than calling a method which implements an interface. (That previous answer was totally valid in the context presented, but the context has changed).
Even if you stay with CollectionBase, you want to handle it in the Add. If you try to remove it in OnInsert, VS will have problems deserializing the collection.
Also, your validationitem needs a Name property or the Collection Editor will display "Myassembly+MyType" as the Name (or a ToString override).
Other issues:
I am not sure your IndexOf will work. The list contains ValidationItems (objects), but you check it for _key (string). This will not matter if you change to Collection(Of T) which implements it for you.
The simple ctor is needed by the Collection Editor, not serialization. But the important thing is that it is there.
As for the comment about all Zeroes coming back - that is because your ValidationItem is not yet decorated for designer serialization. Maybe not the Collection Property either, that isnt shown.

A class can only be a template for a single object not a template for a collection

I have a simple class List.vb which is the following:
Public Class List
Public fList As List(Of Integer)
Public Sub New()
fList = New List(Of Integer)
fList.Add(1)
fList.Add(2)
fList.Add(3)
fList.Add(4)
fList.Add(5)
End Sub
End Class
The Console application is using this class like the following:
Module Module1
Sub Main()
Dim fObject As List = New List
Dim cnt As Integer = 0
For Each x As Integer In fObject.fList
Console.WriteLine("hello; {0}", fObject.fList.Item(cnt).ToString())
cnt = cnt + 1
Next
Console.WriteLine("press [enter] to exit")
Console.Read()
End Sub
End Module
Can I change the class code so that List.vb is a list(of integer) type?
This would mean that in the Console code I could replace In fObject.fList with just In fObject?
Or am I barking up the wrong tree - should classes be single objects and lists should be collections of classes ?
Yes, you can do that. In order for an object to be compatible with For Each, it must have a GetEnumerator function:
Public Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
Return New IntListEnum(fList)
End Function
The IntListEnum class must, in turn, implement IEnumerator, like this:
Public Class IntListEnum Implements IEnumerator
Private listInt As List(Of Integer)
Dim position As Integer = -1
Public Sub New(ByVal fList As List(Of Integer))
listInt = fList
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
position = position + 1
Return (position < listInt.Count)
End Function
Public Sub Reset() Implements IEnumerator.Reset
position = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return listInt(position)
Catch ex As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
Now you can make fList private, and iterate your List as follows:
For Each x As Integer In fObject
You can see a complete example here.
The answer that dasblinkenlight has provided is excellent, but if all you need is a list that of integers that is pre-populated, you can just inherit from List(Of Integer) and then have the class populate itself in the constructor:
Public Class List
Inherits List(Of Integer)
Public Sub New()
Add(1)
Add(2)
Add(3)
Add(4)
Add(5)
End Sub
End Class
When you inherit from List(Of Integer), your class automatically gets all of the functionality implemented by that type, so your class also becomes a list class that works the same way. Then, you can just use it like this:
Dim fObject As New List()
For Each x As Integer In fObject
Console.WriteLine("hello; {0}", x)
Next

Can't create a Collection of Inherited Classes

Maybe I just don't know what to search for, but I'm going a little bonkers here trying to figure out how to create a collection of inherited classes. The base class, I will never use.
Basically, I have 3 components:
A base class call ImageFormat
Child classes of ImageForm
Code in Sub Main() to loop create a
collection and loop through it.
So it does it, #3. The problem is that it always gets the last item added to the collection and uses it's values only.
Here's my Base Class:
Public MustInherit Class ImageFormat
Protected Shared _extentions As String()
Protected Shared _targettype As String
Protected Shared _name As String
Public ReadOnly Property Extentions As String()
Get
Return _extentions
End Get
End Property
Public ReadOnly Property TargetType As String
Get
Return _targettype
End Get
End Property
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
End Class
And here are the child classes:
Class WindowsEnhancedMetafile
Inherits ImageFormat
Sub New()
_extentions = {"EMF"}
_targettype = "jpg"
_name = "Windows Enhanced Metafile"
End Sub
End Class
Class WindowsBitmap
Inherits ImageFormat
Sub New()
_extentions = {"BMP", "DIB", "RLE", "BMZ"}
_targettype = "jpg"
_name = "Windows Bitmap"
End Sub
End Class
Class WindowsMetafile
Inherits ImageFormat
Sub New()
_extentions = {"WMF"}
_targettype = "jpg"
_name = "Windows Metafile"
End Sub
End Class
(don't know if these child classes need to different, like just instantied from ImageFormat type or Singleton patterns - would appreciate anything thoughts you have on this)
Then, my routine is:
Sub Main()
Dim imgFormats As New List(Of ImageFormat)
imgFormats.Add(New WindowsBitmap)
imgFormats.Add(New WindowsMetafile)
imgFormats.Add(New WindowsEnhancedMetafile)
Dim name As String = String.Empty
For Each imgFormat In imgFormats
name = imgFormat.Name
Console.WriteLine(name)
Next
Console.ReadLine()
End Sub
This returns Windows Enhanced Metafile three times at the Console. What am I doing wrong here?
The three properties:
Protected Shared _extentions As String()
Protected Shared _targettype As String
Protected Shared _name As String
Are marked as Shared - they belong to the class not the object.
Each time you assign a new value to _name it overrides the old value, thus why you get the same name printed each time.
It should be:
Protected _extentions As String()
Protected _targettype As String
Protected _name As String
Well, your _name et al are Shared, which means they are class-level variables. When you're adding WindowsEnhancedMetafile, it happens to overwrite these fields with WMF-specific information. If you changed your code to:
imgFormats.Add(New WindowsMetafile)
imgFormats.Add(New WindowsEnhancedMetafile)
imgFormats.Add(New WindowsBitmap)
you would've had "Windows Bitmap" printed three times.
All you have to do is to change your field declarations to
Protected _extentions As String()
Protected _targettype As String
Protected _name As String