Observe List(Of) additions - vb.net

I have a List (Of customclass).
Somewhere within my code, items are added to this List although they should not.
My code is huge, so I can't easily debug where this occurs.
I was therefore thinking of creating an extension that I can easily break in when an insert / add occurs when I don't expect it.
Can anybody tell me if this is possible, and if yes, how?
I hope that I can then somehow detect the caller (the function) where the additions occur.
Thank you.

I think I already have it:
Imports System.Collections.ObjectModel
Public Class clsCellListExtender
Public Class List(Of T)
Inherits Collection(Of T)
Private _iID As Integer = 0
Protected Overrides Sub InsertItem(index As Integer, item As T)
'your checks here
If TypeOf (item) Is clsCell Then
_iID += 1
Dim nCell As clsCell = TryCast(item, clsCell)
nCell.TempID = _iID
End If
MyBase.InsertItem(index, item)
End Sub
End Class
End Class
I declare my list as clsCellListExtender.List(Of clsCell).

Related

How to hold a reference to a field in VB?

In VB, I have a class that does some standard validations. What I'd LIKE to do is to declare some variables, then create instances of a validator class that include pointers to the variables, and then at some later time execute the validators to test the values in the fields that are pointed to.
Something like this:
public class MyData
public property foo as string
public property bar as string
dim vfoo as validator
dim vbar as validator
public sub new()
vfoo=new validator(&foo) ' i.e. & operator like in C
vbar=new validator(&bar)
end sub
public sub validate()
vfoo.validate
vbar.validate
end sub
end class
public class validator
dim _field as string* ' i.e. * like in C
public sub new(field as string*)
_field=field
end sub
public sub validate
if string.isnullorempty(_field) then
throw SomeException
else if not SomeOtherTest(_field) then
throw SomeOtherException
end sub
The catch is that, to the best of my knowledge, there is nothing like C pointers in VB. Is there any reasonably easy way to do this?
At present I am passing in the field values at the time I call the validate() function, but this is not ideal because I would like to be able to create a List of validators specific to a given caller, and then loop through the List. But at the time I loop, how would I know which value from MyClass to pass in, unless I had a giant select statement keying off some "field code"? (And of course in real life, there are not just two fields like in this example, there are quite a few.)
Am I just having a brain freeze and there's an easy way to do this? Or can this not be done in VB because there are no such thing as pointers?
Like Java, VB doesn't make direct use of pointers (it compensates where it can with library/framework calls). In the context of a garbage-collected language, I can't imagine that this style of validation would work out well.
But for fun, maybe a lambda-based solution could suit?:
Public Class MyData
Public Property foo As String
Public Property bar As String
Dim vfoo As validator
Dim vbar As validator
Public Sub New()
vfoo = New validator(Function() foo)
vbar = New validator(Function() bar)
End Sub
Public Sub validate()
vfoo.validate()
vbar.validate()
End Sub
End Class
Public Class validator
ReadOnly _fieldFunc As Func(Of String)
Public Sub New(fieldFunc As Func(Of String))
_fieldFunc = fieldFunc
End Sub
Public Sub validate()
Dim _field = _fieldFunc()
If String.IsNullOrEmpty(_field) Then
Throw New Exception("NullOrEmpty")
ElseIf Not SomeOtherTest(_field) Then
Throw New Exception("SomeOtherTest")
End If
End Sub
Public Function SomeOtherTest(f As String) As Boolean
Return True
End Function
End Class

VB.NET setting class property initial value

When creating a object based on a class. There are certain properties that I prefer to not be value 0 or nothing. So I would like to set the initial value to 1.
Is this best done via the constructor?
Class Product
Public Property Price As Decimal
Public Sub New()
Price = 1
End Sub
End Class
Or can you also write it as following? Does this second version make the value fixed at 1 or can you also alter the value if It's written like this?
Class Product
Public Property Price As Decimal = 1
End Class
Either way you do it, it'll function the same, however do defer to how your team normally does it to maintain consistency.
However, if you do have instances where you may open up the constructor to allow setting of those properties on initialization based on some argument given to the constructor, I would opt to always setting it in the constructor for consistency. If the property always has a default value of X on initialization then inline it at the top so it stands out.
Basic Example:
Class Product
Public Property Price As Decimal = 1
Public Property Quantity As Integer
Public Sub New()
Quantity = 0
End Sub
Public Sub New(quantity As Integer)
Quantity = quantity
End Sub
End Class
At the end its the same, in both cases you can change the values.
No difference, you can alter the value unless it's const or readonly. If you do the second, the compiler will sort of convert it like your first version. Here's a little program that'll show you. This will display 0 and then 1.
Module Module1
Sub Main()
Dim o As New B
Console.ReadLine()
End Sub
End Module
MustInherit Class A
Public Sub New()
Show()
End Sub
Public MustOverride Sub Show()
End Class
Class B
Inherits A
Private test As Integer = 1
Public Sub New()
MyBase.New()
' Value for test is being set here
Show()
End Sub
Public Overrides Sub Show()
Console.WriteLine(test)
End Sub
End Class

Setting Up These Types While Keeping It Properly Structured

I'm completely stuck in a situation and I have no idea on where to go from here. I'm creating a very large project, so my goal is to keep the code itself as clean as possible and keeping as many hacks as possible out of the mix.
Here is the situation.
I have a class called Woo_Type, it is the parent of my many derived classes.
Public MustInherit Class Woo_Type
Private Shared TypeList As New Dictionary(Of String, Woo_Type)
Public MustOverride Sub SetValue(ByVal val As Object)
Public MustOverride Function GetValue() As Object
Public Shared Function GetTypeFromName(ByVal name As String) As Woo_Type
Return TypeList(name)
End Function
Public Shared Sub AddType(ByVal name As String, ByVal def As Woo_Type)
TypeList.Add(name, def)
End Sub
End Class
I have many classes that Inherit from Woo_Type that have similar structures to this:
Public Class Woo_tpInt
Inherits Woo_Type
Private value As Integer = 0
Public Overrides Function GetValue() As Object
Return value
End Function
Public Overrides Sub SetValue(val As Object)
value = val
End Sub
End Class
I want to be able to do things like:
Woo_Type.GetTypeFromName("int")
And have it return something like the class or something...
At this point I'm really confused as to what I want and I didn't know if anybody had any suggestions. To make sure that GetTypeFromName worked correctly, I had in an Initializer sub the following:
Public Sub InitializeTypes()
Woo_Type.AddType("int", Woo_tpInt)
Woo_Type.AddType("String", Woo_tpInt)
End Sub
But I quickly realized that-that obviously doesn't work either.
So this may seem confusing but I'm basically wondering how to better structure this so that everything works...
What do you want to do with the result? Are you sure you don't simply need generics?
Public Class WooType(Of T)
Public Property Value As T
End Class
Public Class Test
Public Sub Foo()
Dim int As New WooType(Of Integer)
int.Value = 42
Dim str As New WooType(Of String)
str.Value = "Forty-Two"
End Sub
End Class
If what you want to do is get the type itself (as opposed to an object), I would recommend using reflection rather than trying to reinvent the wheel. For instance, to get the Woo_tpInt type, you could do this:
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType("WindowsApplication1.Woo_tpInt") ' Change WindowsApplication1 to whatever your namespace is
If you want to use a shorter name like "int" to mean "WindowsApplication1.Woo_tpInt", you could create a dictionary to store the translation table, for instance:
Dim typeNames As New Dictionary(Of String, String)
typeNames.Add("int", GetType(Woo_tpInt).FullName)
Dim a As Assembly = Assembly.GetExecutingAssembly()
Dim t As Type = a.GetType(typeNames("int"))

VB Polymorphism Constructors Default and Properties. Similar Class to Listbox

I've been banging my head against a wall for sometime on this one.
I'm trying to create a class for storing data on People with another class to store their Bank Transactions.
Ideally, this all be hidden away and leave only simple statments, declarations and functions available to the programmer. These will include:
Dim Clients As New ClientList
Clients.Count 'readonly integer
Clients.Add("S")
Clients.Refresh()
Clients(n).Remove()
Clients(n).Transaction.Add()
Clients(n).Transaction(n).Remove()
I know this is possible as these exist in the Listbox Class though can't figure out how it's done.
Any help would be appreciated.
Thanks in advance!
Create a Transaction and a Client class
Public Class Transaction
'TODO: Implement Transaction
End Class
Public Class Client
Public ReadOnly Transactions As List(Of Transaction) = New List(Of Transaction)
Public Sub New(ByVal name As String)
Me.Name = name
End Sub
Public Name As String
End Class
Create a ClientList class
Public Class ClientList
Inherits List(Of Client)
Public Overloads Sub Add(ByVal name As String)
Add(New Client(name))
End Sub
Public Sub Refresh()
' Do what ever you want Refresh to do
End Sub
End Class
You can then use the client list like this
Dim clients As New ClientList
clients.Add("S")
' Or
clients.Add(New Client("T"))
Dim n As Integer = clients.Count
Dim m As Integer = clients(0).Transactions.Count
clients.Refresh()
clients.RemoveAt(5)
clients(n - 1).Transactions.Add(New Transaction())
clients(n - 1).Transactions.RemoveAt(2)
Dim name As String = clients(0).Name
Dim client As Client = clients(0)
Use the generic List(Of T) class, specialized to hold your Client objects. It already provides all of the methods you want without your having to write a single line of code!
So you would first write a Client class that contained all of the properties (data) and methods (actions) relating to a "client":
Public Class Client
Public Property Name As String
Public Property AmountOwned As Decimal
Public Sub Bill()
BillingManager.BillClient(Me)
End Sub
' ... etc.
End Class
Then, you would create the List(Of T) to hold all of your instances of the Client class:
Dim clients As New System.Collections.Generic.List(Of Client)
If, for whatever reason, you needed to specialize the behavior of the Add, Remove, etc. methods provided by the collection class, or add additional methods, you would need to change strategies slightly. Instead of using List(Of T), you would inherit from Collection(Of T) and create a custom collection class like so:
Public Class ClientCollection
Inherits System.Collections.ObjectModel.Collection(Of T)
' ... customize as desired ...
End Class
The WinForms ListBox class doesn't do it exactly like this because it was written before generics were introduced to the framework. But since they're here now, and you should always use them when possible, you can completely ignore how WinForms does things.

.net dynamic loading

I've seen some other responses about this and they talk about interfaces but I'm pretty sure you can do this with classes and base classes but I can't this to work.
Public Class Behavior
Private _name As String
Public ReadOnly Property Name As String
Get
Return _name
End Get
End Property
Public Property EditorUpdate As Boolean
Public Sub New(ByVal name As String)
_name = name
EditorUpdate = False
End Sub
Public Overridable Sub Update()
End Sub
' runs right away in editor mode. also runs when in stand alone game mode right away
Public Overridable Sub Start()
End Sub
' runs after game mode is done and right before back in editor mode
Public Overridable Sub Finish()
End Sub
' runs right when put into game mode
Public Overridable Sub Initialize()
End Sub
' runs when the game is complete in stand alone mode to clean up
Public Overridable Sub Destroy()
End Sub
End Class
Public Class CharacterController
Inherits Behavior.Behavior
Public Sub New()
MyBase.New("Character Controller")
End Sub
Public Overrides Sub Update()
' TODO: call UpdateController()
' THINK: how can UpdateController() get the controller entity it's attached to?
' Behaviors need a way to get the entity they are attached to. Have that set when it's assigned in the ctor?
End Sub
End Class
Dim plugins() As String
Dim asm As Assembly
plugins = Directory.GetFileSystemEntries(Path.Combine(Application.StartupPath, "Plugins"), "*.dll")
For i As Integer = 0 To plugins.Length - 1
asm = Assembly.LoadFrom(plugins(i))
For Each t As Type In asm.GetTypes
If t.IsPublic Then
If t.BaseType.Name = "Behavior" Then
behaviorTypes.Add(t.Name, t)
Dim b As Behavior.Behavior
b = CType(Activator.CreateInstance(t), Behavior.Behavior)
'Dim o As Object = Activator.CreateInstance(t)
End If
End If
Next
Next
When it tries to convert whatever Activator.CreateInstance(t) returns to the base class of type Behavior I'm getting invalid cast exception. That type should be of CharacterController which is defined as a child of Behavior so why wouldn't it let me cast that? I've done something like this before but I can't find my code. What am I missing?
This may not be an answer to your question (it also might resolve your exception -- who knows), but it is something that needs to be pointed out. These lines:
If t.IsPublic Then
If t.BaseType.Name = "Behavior" Then
Should really be changed to one conditional like this one:
If t.IsPublic AndAlso (Not t.IsAbstract) AndAlso _
GetType(Behavior.Behavior).IsAssignableFrom(t) Then
Otherwise, if somebody defines a random type called "Behavior" in their own assembly and derives it from another type, your code will think it is a plugin. Additionally, if someone derives your Behavior type and then derives that type (two levels of inheritance) this code will incorrectly skip over that type. Using the IsAssignableFrom method is a quick and easy way to ensure that one type does actually derive from the specific type you want (instead of any type that shares the same name), even if there is another type in between your types in the inheritance tree. The additional check against t.IsAbstract will also ensure that you don't try to instantiate an abstract subtype of your base plugin type.
This works for me:
Dim ctor As Reflection.ConstructorInfo = _
t.GetConstructor(New System.Type() {})
Dim o As Object = ctor.Invoke(New Object() {})
Dim plugin As Plugin = TryCast(o, Plugin)
(If I find t, I invoke the parameterless constructor.)
[I just realized this is probably what Activator.CreateInstance does, so I replaced my code with yours and it worked your way -- so this probably won't help you]