Cast of two custom types in VB.NET - vb.net

I need to cast, in the better way, two objects of two types of two custom-classes (in VB.Net):
The code:
Public Class pluto
Public Sub New(ByVal campoPippoPass As String)
_campoPippo = campoPippoPass
End Sub
Private _campoPippo As String = ""
Public Property campoPippo() As String
Get
Return Me._campoPippo
End Get
Set(ByVal value As String)
If Not Object.Equals(Me._campoPippo, value) Then
Me._campoPippo = value
End If
End Set
End Property
End Class
Public Class pippo
Public Sub New(ByVal campoPippoPass As String)
_campoPippo = campoPippoPass
End Sub
Private _campoPippo As String = ""
Public Property campoPippo() As String
Get
Return Me._campoPippo
End Get
Set(ByVal value As String)
If Not Object.Equals(Me._campoPippo, value) Then
Me._campoPippo = value
End If
End Set
End Property
End Class
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim a As New pippo("ciao")
' here I have the error 'invalid cast'
Dim c As pluto = CType(a, pluto)
MsgBox(c.campoPippo)
End Sub
How can I convert "c" into an "a" type object? Is there another way than writing the following?
Dim c As New pluto(a.campoPippo)
In the case of a more complex class, it could be more easy if there was a function for the conversion.

Firstly, I'm assuming the line: Dim c As pluto = CType(b, pluto) is a mistype and should actually be Dim c As pluto = CType(a, pluto)?
You can't cast one class to another unless they're related. You might need to explain what you're trying to do otherwise my answer would be, why are you creating the different classes pluto and pippo if they seem to be identical? Just create the one class and create two objects of it.
If you do need separate classes, maybe they are related in some way and you could make pippo inherit from pluto? Or make both of them implement the same interface.
In general I'd also suggest that it might be worth translating your class/variable names to English since that might make it easier for people to understand what you're trying to do.

Related

Showing classes to user and instantiating selected type

I'm starting to learn about Reflection in VB.NET, and I have a little example problem I'm working on to understand some concepts.
So I have one interface implemented by three classes:
Public Interface IVehicle
Sub SayType()
End Interface
Public Class Bike
Implements IVehicle
Public Sub SayType() Implements IVehicle.SayType
MsgBox("I'm a bike")
End Sub
End Class
Public Class Car
Implements IVehicle
Public Sub SayType() Implements IVehicle.SayType
MsgBox("I'm a car")
End Sub
End Class
Public Class Plane
Implements IVehicle
Public Sub SayType() Implements IVehicle.SayType
MsgBox("I'm a plane")
End Sub
End Class
I would like the user to select one type of vehicle of all the vehicles available, instantiate one object of this type and call its method "SayType".
So, with this situation, I have 2 questions
The 1st one: I have thought about filling one ComboBox control with all the classes which implement the interface IVehicle. I have searched how to do so with reflection, and I've came up with this solution:
Private Function ObtainVehicleTypes() As IEnumerable(Of Type)
Dim types As IEnumerable(Of Type) = _
Reflection.Assembly.GetExecutingAssembly.GetTypes.Where(Function(t) _
t.GetInterface("IVehicle") IsNot Nothing)
Return types
End Function
With those types, I fill the ComboBox like this, which also works fine:
Private Sub AddTypesOfVehicles()
Dim types As IEnumerable(Of Type) = ObtainVehicleTypes()
For Each t As Type In types
ComboBox1.Items.Add(t.Name)
Next
End Sub
The problem is that, when I try to retrieve the item selected by the user and obtain the type asociated like shown below, I get Nothing, since the String doesn't contain the AssemblyName, only the Class name:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim type As Type = TryCast(ComboBox1.SelectedItem, Type) 'Here I get Nothing
Dim v As IVehicle = TryCast(Activator.CreateInstance(type), IVehicle)
v.SayType()
End Sub
I have also tried to to add this to the combobox:
For Each t As Type In types
ComboBox1.Items.Add(t) 'Adding the type, not only its name.
Next
But then it displays the AssemblyName to the user, which I want to avoid.
So, the question is... how would you do to show the classes to the user and the retrieve them correctly to instantiate an object of the chosen class?
The 2nd question: Do you consider this as a good approach? Would you suggest something simpler?
Thanks!
I do not understand the need of the method SayType on the interface. All types implements the GetType method which will return the info you'll need.
Dim vehicles As IVehicle() = New IVehicle() {New Bike(), New Car(), New Plane()}
For Each vehicle As IVehicle In vehicles
MsgBox(String.Format("I'm a {0}", vehicle.GetType().Name.ToLower()))
Next
'This will produce:
'------------------
'I'm a bike
'I'm a car
'I'm a plane
'------------------
This is how you could populate the combobox:
Dim t = GetType(IVehicle)
Dim list As List(Of Type) = Assembly.GetExecutingAssembly().GetTypes().Where(Function(x As Type) ((x <> t) AndAlso t.IsAssignableFrom(x))).ToList()
Me.ComboBox1.DataSource = list
Me.ComboBox1.DisplayMember = "Name"
And to retrieve the type:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles saveButton.Click
If (Me.ComboBox1.SelectedIndex <> -1) Then
Dim t As Type = TryCast(Me.ComboBox1.SelectedItem, Type)
If (Not t Is Nothing) Then
MsgBox(t.FullName)
End If
End If
End Sub
Edit
A more real-world example of an IVehicle interface would be something like:
Public Interface IVehicle
ReadOnly Property Manufacturer() As String
ReadOnly Property Model() As String
Property Price() As Decimal
End Interface
combobx problem its Excellent answered by #Bjørn-Roger Kringsjå.
Here are additional improvements:
ObtainVehicleTypes:
Private Function ObtainVehicleTypes() As IEnumerable(Of Type)
Dim IVehicleType = GetType(IVehicle)
Dim types As IEnumerable(Of Type) = _
Reflection.Assembly.GetExecutingAssembly.GetTypes.Where(
Function(t) IVehicleType.IsAssignableFrom(t) AndAlso t.IsClass = True)
Return types
End Function
Private Sub AddTypesOfVehicles()
Dim types As IEnumerable(Of Type) = ObtainVehicleTypes().ToArray()
ComboBox1.DisplayMember = "Name"
ComboBox1.DataSource = types
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim type As Type = TryCast(ComboBox1.SelectedItem, Type)
Dim v As IVehicle = TryCast(Activator.CreateInstance(type), IVehicle)
v.SayType()
End Sub

Working with bindinglist

I have a datagridview and a bindinglist. They work together pretty ok, but I want to make the properties appear in the rows, not on the column. Is there any way to achieve that ?
My code for anyone who is interested.
Public Class Form1
Dim listaBindingSource As New BindingList(Of pessoa)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim b1 As New pessoa()
listaBindingSource.Add(b1)
dgv.DataSource = listaBindingSource
End Sub
End Class
Public Class pessoa
Dim sells_Month1 As String
Public Sub New() 'ByVal nome_fora As String)
sells_Month1 = "0"
End Sub
Property vendas1 As String
Get
Return sells_Month1
End Get
Set(value As String)
sells_Month1 = value
End Set
End Property
The other properties are vendas2, vendas3.. and are the same as this one.
Edit:
I´m kind of lost here. What I want is to make the values of the properties of my objects appear on some kind of data visualizer. When I add new objects on the list, they appear on this data visualizer and when I change the values of the cells there, the values of the properties change. Anyone has a good sugestion ? Apparentely dgv is not the way to go.
Thanks,
Ricardo S.
I want to make the properties appear in the rows´ headers, not on
the column.
I'm afraid this is not possible, there is no built-in solution for that in DataGidView. You can display the properties in columns only.
To control the text displayed in the column header, try to set the DisplayName attribut:
<System.ComponentModel.DisplayName("DisplayedText")>
Property vendas1 As String
Get
Return sells_Month1
End Get
Set(value As String)
sells_Month1 = value
End Set
End Property
Or if you import System.ComponentModel namespace.
<DisplayName("DisplayedText")>
Property vendas1 As String
Get
Return sells_Month1
End Get
Set(value As String)
sells_Month1 = value
End Set
End Property

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.NET get type of derived generic list class from list item method

Public Class notifierMain
Public Class Contacts
Inherits List(Of row)
Public Sub New()
Dim r As New row()
Me.Add(r)
End Sub
Public Class row
Public Sub Validate()
Dim curType As String = Me.GetType().ToString
End Sub
End Class
End Class
Public Class MyContacts
Inherits contacts
End Class
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim c As MyContacts = New MyContacts()
c(0).Validate()
End Sub
End Class
When I debug this winforms application I get curType = "notifier.notifierMain+Contacts+row"
I want to the Validate function to know it is in MyContacts. How do I do this?
You're tostring()'ing gettype which returns a property called full name.
just check the .Name after get type and that'll have the result you want.
btw: this is a weird example, if you want validate() to return the name of the class you'll have to declare it as a function.
:)
The Me.GetType() is always going to return the type of the class it is enclosed in.
You will need to change Validate to a function and pass in the type of object being validated, but then you might as well call c(0).GetType() outside if the validation anyway!
See MSDN documentation for GetType
You can explore your generic type as shown in this MSDN article:
http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx
Hope this helps.

Vb.net Custom Class Property to lower case

I am trying to create a settings class.
The Property Test() is a list of strings.
When I add a string such as: t.test.Add("asasasAAAAA")
I want it to autmatically turn lowercase.
For some reason it is not. Any Ideas?
p.s.
using t.test.Add(("asasasAAAAA").ToLower) will not work for what I need.
Thank you.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim t As New Settings
t.test.Add("asasasAAAAA")
t.test.Add("aBBBBBAAAAA")
t.test.Add("CCCCCsasAAAAA")
End Sub
End Class
Public Class Settings
Private strtest As New List(Of String)
Public Property test() As List(Of String)
Get
Return strtest
End Get
Set(ByVal value As List(Of String))
For i As Integer = 0 To value.Count - 1
value(i) = value(i).ToLower
Next
strtest = value
End Set
End Property
End Class
ashakjs
That's the reason: set accessor of your property is actually never called.
when you use t.test.Add("asasasAAAAA") you are actually calling a get accessor, which returns a list, after that specified string is added to this list, so .ToLower function is never called.
Simple way to fix this:
Dim list as New List(Of String)
list.Add("asasasAAAAA")
list.Add("aBBBBBAAAAA")
list.Add("CCCCCsasAAAAA")
t.test = list
Alternatively, you can implement your own string list (easiest way - inherit from Collection (Of String)), which will automatically convert all added string to lower case.
What you are trying to do and what you are doing don't match. To do what you want, you need to create your own collection class extending the generic collection - or provide a custom method on your settings class which manually adjusts the provided string before adding it to the local (private) string collection.
For an example of the second option, remove the public property of the settings class which exposes the list of string and use a method like the following:
Public Sub Add(ByVal newProp As String)
strtest.Add(newProp.toLower())
End Sub