Accessing an element of a custom type list by property value - vb.net

Let's say I have a class called ControlInfo, which has the following properties:
Public Property Control As Control
Public Property ControlState As Int32
Now I want to create a method for accessing a specific instance of ControlInfo from a List, so I do this:
Public Function GetInstance(control As Control) As ControlInfo
For Each c As ControlInfo In list
If c.Control.Name = control.Name Then
Return c
End If
Next
Return Nothing
End Function
Is there a better way to access specific instance from a list of a custom class based on its property value? Is the loop approach bad for performance?
Sidenote: I have also considered the implementation of a Dictionary other than a List (so I would access an instance via a key, which can be a lot better than looping through all the values), but I feel that if I resort to that I would be avoiding a problem instead of solving it. Maybe I am being paranoid but I would like to know other valid approaches here, and be more certain of what should/shouldn't be done.
Thanks.

Related

Why to use GET & SET methods while defining properties in VB.Net?

I am bit confused over the need to use GET & SET methods in VB.net. I want to discuss two cases in this connection: firstly when we declare the property as PUBLIC and next when we declare the property as PRIVATE.
What is I find is when I define a property as public I can directly set and access the values of that property without using the GET/SET methods --- quite simple: See below
Module Program
Sub Main()
Dim t As New test()
t.name = "Roy" 'Label 1
Console.WriteLine("t.name = {0}", t.name)
Console.ReadLine()
End Sub
End Module
Class test
Public Property name() As String
End Class
When I declare that same property as private, as shown below, I can still set and access the value of private property by simply using a constructor and a public subroutine. See below:
Module Program
Sub Main()
Dim t As New test()
t.printValue()
Console.ReadLine()
End Sub
End Module
Class test
Private Property Name() As String
Sub New()
Name = "Roy" 'Label 2
End Sub
Public Sub printValue()
Console.WriteLine("Value stored in NAME is: {0}", Name)
End Sub
End Class
So my question is why at all do we need to use the GET/SET methods? I understand that whenever an assignment happens to a property the SET method is implicitly called...but can you please help me understand cases where we MUST explicitly use the GET/SET methods? Or it is that using GET/SET is more of a choice? Validation is one thing that can be added easily at a later stage if one uses GET/SET but then is that the only reason? PLs give your views.
Also, I came across the following two related questions in stackoverflow (for different languages though): Links below:
Why to use getter and setter methods to set class properties?
Why use getters and setters/accessors?
But i could not understand most of the reasons justifying the usage of the GET/SET methods. For example if we dont use the GET/SET method then we are exposing the property to the outside world - meaning it can be directly accessed from outside the class. But then this is true only for PUBLIC properties as PRIVATE properties cannot be directly accessed from outside the class. Similarly in the second link the author mentions the following as a reason to use GET/SET: Providing a debugging interception point for when a property changes at runtime - debugging when and where a property changed to a particular value can be quite difficult without this in some languages. What exactly does this mean --- any simple real life example?
A property is a wrapper around a field, i.e., a class or struct variable. It provides a getter and/or a setter method to access this variable. (You can also have a read-only property returning the result of a simple evaluation not bound to a single field.)
The getters and setters are implicitly called when reading from, respectively writing to properties.
So, the question is not whether to use getters and setters or not, but whether to access fields directly or via a property.
You can declare a property like this, by declaring a field and writing the getter and setter explicitly.
Private _prop1 As String ' Backing field
Public Property Prop1() As String
Get
Return _prop1
End Get
Set(ByVal value As String)
_prop1 = value
End Set
End Property
or use an Auto-Implemented Property
Public Property Prop1 As String
Both declarations are equivalent. The auto-implemented property implicitly declares a backing field and implements the getter and the setter accordingly.
It can make sense to declare a property as private when you use it only inside the class where it is declared. This still provides the advantages described in the links you provided because this property still hides the details of accessing a field, does validations, etc.; however, it does not forbid the direct access to the backing field inside the class. So, you need to be more disciplined with private properties.
What does a property mean for debugging? You can easily set a breakpoint inside a getter or setter to detect accesses to a property. You cannot set a breakpoint on a field because a field is never executed. It is just a declaration.
You can also add a System.Diagnostics.Debug.Writeline("=====> test") (writes to the Output window) or do some logging in getters and setters.
See also: Tutorial: Learn to debug Visual Basic code using Visual Studio
When using Windows Forms Data Binding or WPF Data Binding properties are required. They also allow change notification.
Dynamically Calculated Values
I didn't read those links, but one reason you might want to implement your own getters & setters is that you may want to return something that requires some type of calculation or manipulation. For example, suppose you have item Sale with properties RawPrice, SalesTax, and FinalPrice. However, you need/choose to dynamically calculate the final price (based on variable sales tax) each time. So you first set the RawPrice, and then query FinalPrice, which returns RawPrice + SalesTax, but SalesTax gets dynamically calculated based on some other property like country of origin etc.
Alternate View of Data
Another reason you might want to do this is to provide another view of the same core data. For example, if your data was an HTML page, perhaps one property returns the normal string value, while another "no-HTML" Property has a custom Getter that performs some regex to remove all HTML tags and return a plain-text variation. This allows you to keep all related code inside of a sub-assembly, rather than having your main program do various manipulations.
Code Portability
This can make your life a lot easier down the road because of code portability. Your code is now more easily re-usable in other projects, since all you need is that one assembly.
Private Variables vs Properties
If I'm doing something that calls for a class with properties like that, there's good chances it's going to have methods, too. Those methods are almost always going to require creating private variables that nothing outside the assembly needs to know about. However, in such cases, they are not going to be private properties but rather simply private variables. For example, instead of Private Property Name() As String, with its implied auto-implemented backer variables with getters & setters, I would instead just say Private Name() As String, which would be equivalent to Dim Name() As String. You can use variables, constants etc. within your class just as you normally would, and, by default, the rest of the world won't know anything about them.
I'm not sure why you'd use a private Property. Maybe there's a good reason; I just don't know what it is. Most of the time, a private variable is probably what you really want. If you think there's a reason that you actually need a Private Property, I'm curious to hear your thinking on it. (I'm always open to a new way of thinking!)
History
Auto-implemented properties were not present in Visual Basic .NET for many years. In the past, you had no choice but to use GET/SET. So it's a more recent development for VB.NET to be able to simply declare a property as you do in your first code example, and for the runtime to automatically generate the backer variables.

How do I assign an object type dynamically?

I am trying to loop through all of the controls in a panel. Some of the controls as classes that I created. In those classes, I want a subroutine run when the object is removed. So I am trying to create a temporary object that I can use to run that routine.
For Each window As Control In main_window.Controls
If window.Handle = hdl Then
Dim temp_window as window.getType()
temp_window.close_me()
main_window.Controls.Remove(window)
End If
Next
However, the getType assignment is not allowed.
How can I accomplish this?
Object.GetType is not what you want, it returns the Type instance of the object which contains meta data of that type, normally used for reflection.
What is the actual type that you want? It has to have a close_me method. You could use OfType:
Dim windowsToClose = main_window.Controls.OfType(Of YourWindowType)().
Where(Function(w) w.Handle = hdl).
ToArray()
For Each window In windowsToClose
window.close_me()
main_window.Controls.Remove(window)
Next
Your For Each doesn't work for another reason: you can't remove items from the collection while you are enumerating it. Above approach stores the windows you want to remove in an array.
The right way to do this is to use a base class that your controls Inherit or an interface that your controls Implement with close_me on the base or interface. Then, you can TryCast each member of Controls to the base or interface and, if it succeeds, call close_me on it. If you use the base class approach, you may wish to make it abstract (MustInherit) and then close_me would be MustOverride, depending on if the behavior should be different in each derived type.
e.g. assuming you use ICloseable,
Interface ICloseable
Sub close_me()
End Interface
'...
For Each window As Control In main_window.Controls
If window.Handle = hdl Then
Dim asCloseable = TryCast(window, ICloseable)
If asCloseable IsNot Nothing Then
asCloseable.close_me()
EndIf
EndIf
Next

Initialize a value for a shared property

I want to use a counter for how many objects are created from a single class, so I thought that a Shared Property would be the way to go. But, VB doesn't like that and says, "Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class"
Private _Length As Integer = 0
Public Shared Property Length As Integer
Get
Return _Length
End Get
Set(value As Integer)
_Length = value
End Set
End Property
Is there a way to initialize a shared variable, in this case to zero, and have the Property still function correctly. I used the Java get/set methodology (getLength()/setLength())and that worked fine, but I'm sure that it would be frowned up by VBers.
Also, using two variables to get/set one that is actually used seems a bit redundant. I see why it is used in the VB methodology because of the recursion that happens, but it does look strange.
The backing field _Length must also be shared.
Private Shared _Length As Integer = 0
using two variables to get/set one that is actually used seems a bit
redundant.
You don't have two variables just one which is _Length, a property just manages how you can access that variable. Note that even auto implemented properties like this use a backing-field:
Public Property Length As Int32
You just don't see it since it will be generated for you.

Dynamic objects or properties?

I apologize for the vague question, but I'm unsure how to proceed.
What I need is something that works like a class object with various fields and properties for storing data. But, since not all the fields/properties are known at the compile time, I also need to be able to add and use new fields/properties in runtime.
These objects would later be arranged in lists, sorted by the values in those fields/properties and bound to WPF controls.
For now I'm using just that: class objects with various properties, but I'm starting to run into problems, where I need to add more fields/properties.
Is there something I could use to achieve this in vb.net?
Edit:
Ok, I'll try to illustrate.
Currently I have something like this.
Let's say I have defined an object like this
Public Class DataEntry
Public Property Name As String
Public Property Type As String
Public Property Msc As Integer
End Class
That works fine if I know all the properties I will have at the start. I run into problems if I suddenly need to add another property:
Public Class DataEntry
Public Property Name As String
Public Property Type As String
Public Property Msc As Integer
Public Property AdditionalDescription As String
End Class
Of course, I could recompile the whole thing, but since I don't know all the possible properties I will be needing in the end, I was wondering, maybe there is a way to achieve this from runtime?
Or should I just use complicated heap of arrays instead of custom objects?
It's not possible to add new properties to a class during run time.
If you don't want to add properties to the class ahead of time which you might not use, then you could instead use a dictionary to store 'properties' which you're not aware of until run time.
Public Property RunTimeProperties As New Dictionary(Of String, Object)
A dictionary which holds values of type 'Object' can store just about anything. Strings, Arrays, Lists etc.
RunTimeProperties.Add("Length", 100)
RunTimeProperties.Add("Height", 200)
RunTimeProperties.Add("MiddleName", "Rupert")
RunTimeProperties.Add("SiblingsNames", New String() {"John", "Sarah", "Michael"})
You can use the TryGetValue method to get the values out of the dictionary.
Dim value As Object
If RunTimeProperties.TryGetValue("Length", value) Then
' Length was found in the dictionary
Else
' Length was not found in the dictionary
End If

DataBinding to reference types

I've got some classes that have properties like this, and they work perfectly because they are very normal:
Public Overridable Property CustomerLastName() As String
Get
Return m_CustomerLastName.Value
End Get
Set(ByVal Value As String)
m_CustomerLastName.Value = Value
End Set
End Property
I want to change them to work like this (and don't worry about what IField is, suffice it to say it represents a field in a table):
Public Overridable Readonly Property CustomerLastName() As IField
Get
Return m_CustomerLastName
End Get
End Property
That way, you could do Customer.CustomerLastName.PreviousValue, or Customer.CustomerLastName.IsDirty, etc.
But that doesn't bind correctly. Understandable, since databinding is supposed to be a two-way thing, and there's reflection involved, etc.
Of course it can still be a two-way street, I just need to be able to say, "Hey DataBinding! Look over here!"
So. What do I do here?
Note: Right now, all I'm trying to do is DataBind to a GridView for display purposes. But I want this to be flexible.
(Update re edit) If it is just for display purposes, you can probably just set the ToString() on the class that implements IField.
(original)
No - 2-way data binding wants either INotifyPropertyChanged, or an CustomerLastNameChanged event. You can shim this into a custom model by implementing ICustomTypeDescriptor or TypeDescriptionProvider, but then you need to write your own PropertyDescriptor implementation.
Re IsDirty - that is ShouldSerializeValue in PropertyDescriptor terms.