Is it possible to add an interface to an existing type? - vb.net

I've developed some serialization code for my types. They all share a common interface to facilitate the serialization logic. Would it be possible to also add that interface to some basic types like Integer or String so I could pass one of those basic type values into my serialization logic and have it work? I'm imagining something along the lines of extension methods, but adding an interface rather than a method? I'm sure I could come up with some way to do it using late-binding, but I'd like to avoid that, if possible.

No. It is not possible to extend an existing type to make it implement an interface (short of adding Implements IMyInterface to the top of the code for that type, that is). The closest thing to that would be to create a derived class which adds the interface to the base class. If you override the CType operator you could even make it so values could be seamlessly converted from one type to the other without explicitly casting them. However, since you mentioned String and Integer as the types that you want to extend, that is not even possible. You can't create a new type that inherits from String because String is defined as NotInheritable. Similarly, you can't create a new type that inherits from Integer because Integer is a Structure, not a Class. Structures do not support inheritance.
Therefore, the best option that you have would be to create a new class which wraps the core value, extends it by implementing the interface, and then overrides the CType operator to make it simple to convert between the core type and the wrapper type. For instance, let's say you had an interface like this:
Public Interface IWritable
Sub Write()
End Interface
And you had a method that took an argument of that type, like this:
Private Sub TestWrite(writableObject As IWritable)
writableObject.Write()
End Sub
If you needed to pass an Integer into that method, you could make a wrapper class like this:
Public Class WritableInteger
Implements IWritable
Public Sub New(value As Integer)
Me.Value = value
End Sub
Public Property Value As Integer
Public Sub Write() Implements IWritable.Write
Console.Write(Value)
End Sub
Overloads Shared Widening Operator CType(value As Integer) As WritableInteger
Return New WritableInteger(value)
End Operator
Overloads Shared Widening Operator CType(value As WritableInteger) As Integer
Return value.Value
End Operator
End Class
Since the CType operator is overloaded as Widening, that means that you can convert the value between the two types without casting (even with Option Strict On). For instance, this works:
Dim w As WritableInteger = New WritableInteger(5)
Dim i As Integer = w
w = i
Unfortunately, since TestWrite is asking for an IWritable rather than a WritableInteger, you can't just call TestWrite with an Integer, like this:
Dim i As Integer = 5
TestWrite(5) 'This won't work!
The compiler knows that it needs to convert the Integer to an IWritable object, but since any number of types may implement that interface, it doesn't automatically try to figure out if any of them provide a CType operator for that. Since there may be multiple types that allow widening conversions from Integer to IWritable, it just throws up its hands and cries fowl. Therefore, even though the widening conversion is declared, you still have to explicitly cast the type in a case like that. For instance:
Dim i As Integer = 5
TestWrite(CType(i, WritableInteger))
Or, perhaps more simply:
Dim i As Integer = 5
TestWrite(New WritableInteger(5))
You could make it more convenient by creating overloads for all the common types that will need to be wrapped. For instance, if you created an overload to the TestWrite method, like this:
Public Sub TestWrite(value As Integer)
TestWrite(New WritableInteger(value))
End Sub
Then you could easily call it like this:
TestWrite(5)
Converting back from an IWritable variable to an Integer, though, is even more difficult. For instance:
Dim w As IWritable = New WritableInteger(5)
Dim i As Integer = w ' This won't work!
Dim i2 As Integer = CType(w, Integer) ' Whis won't work either!
If you need to do that, you'd actually have to first cast it to a WritableInteger (and know that it is that type of object in the first place), for instance:
Dim w As IWritable = New WritableInteger(5)
If TypeOf w Is WritableInteger Then
Dim i As Integer = CType(w, WritableInteger)
End If
Unfortunately, there's really no way to make that any easier while still maintaining the safety of the compile-time type checking.
Finally it's also worth mentioning that, if you decide to make a wrapper like that, and the implementation of the interface is the same regardless of the wrapped type, then you could implement it as a generic type, like this:
Public Class Writable(Of T)
Implements IWritable
Public Sub New(value As T)
Me.Value = value
End Sub
Public Property Value As T
Public Sub Write() Implements IWritable.Write
Console.Write(Value)
End Sub
Overloads Shared Widening Operator CType(value As T) As Writable(Of T)
Return New Writable(Of T)(value)
End Operator
Overloads Shared Widening Operator CType(value As Writable(Of T)) As T
Return value.Value
End Operator
End Class
Then you could call the TestWrite method like this:
TestWrite(New Writable(Of Integer)(5))
TestWrite(New Writable(Of String)("Hello World"))

Related

In a generic VB.NET structure, how do I access its explicitly provided constructor?

First of all, what I want to achieve:
I want to extend a value datatype by providing additional properties, especially to validate ranges provided at declaration time. I want the new datatype to be a value type as well.
Compare with Ada:
subtype Day_Number is Integer range 1 .. 31;
Ideal, but obviously not implementable, would be:
Dim DayNumber As Int64 Range 1 To 31
However, I would be happy with:
Dim DayNumber As RangeInt64(1, 31)
It is of no concern, if initialization takes its time. Once ranges are provided, they are considered to be immutable. The datatype from then on is only used to set/get values like with ordinary value types, only that they are subject of being validated against the initially provided range.
My attempt:
Since I cannot inherit from structures in order to expand on them, I tried to incorporate a structure into a structure as a member.
In a module, I have this structure:
Friend Structure SRangeValueType(Of T)
Private lMinimum As T
Private lMaximum As T
Friend Property Minimum As T
Get
Return lMinimum
End Get
Set(tValue As T)
lMinimum = tValue
End Set
End Property
Friend Property Maximum As T
Get
Return lMaximum
End Get
Set(tValue As T)
lMaximum = tValue
End Set
End Property
Friend Sub New(Minimum As T, Maximum As T)
lMinimum = Minimum
lMaximum = Maximum
End Sub
End Structure
I attempt to use this generic structure as a member of another structure (of concrete type Int64):
Public Structure RangeInt64
Private Range As SRangeValueType(Of Int64)
End Structure
However, this is not using the constructor with the two arguments.
Say I want to initialize Range (the only member of the structure RangeInt64) with the values 100 and 200 for Minimum and Maximum, resp.
I am not allowed to use something like:
Private Range As SRangeValueType(Of Int64)(100,200)
What is the correct syntax to provide my values to the generic constructor?
Normally, if you add a constructor to a structure, you can call it using the New keyword:
Dim x As SRangeValueType(Of Int64) ' Calls the default, infered, parameter-less constructor
Dim y As New SRangeValueType(Of Int64)(100, 200) ' Calls the explicitly defined constructor
However, that's not really the problem. The problem is that you are trying to set the default value of a non-shared field in a structure. That is something which is never allowed. All non-shared fields in structures must default to their default value (i.e. Nothing). For instance:
Public Structure RangeInt64
Private x As Integer = 5 ' Error: Initializers on structure members are valid only for 'Shared' members and constants
Private y As New StringBuilder() ' Error: Non-shared members in a structure cannot be declared 'New'
End Structure
And, as you may already know, you cannot override the default, inferred, parameter-less constructor on a structure either:
Public Structure RangeInt64
Public Sub New() ' Error: Structures cannot declare a non-shared 'Sub New' with no parameters
x = 5
y = New StringBuilder()
End Sub
Private x As Integer
Private y As StringBuilder
End Structure
As such, you are stuck. By design, when the default constructor is used, all fields in the structure must always default to Nothing. However, if you really, really need it to be a structure, and you can't just convert it to a class, and you really need to change it's default value, you could theoretically fake it into working by using a property to wrap the field:
Public Structure RangeInt64
Private _Range As SRangeValueType(Of Int64)
Private _RangeInitialized As Boolean
Private Property Range As SRangeValueType(Of Int64)
Get
If Not _RangeInitialized Then
_Range = New SRangeValueType(Of Int64)(100, 200)
_RangeInitialized = True
End If
Return _Range
End Get
Set(value As SRangeValueType(Of Int64))
_Range = value
End Set
End Property
End Structure
It should go without saying, though, that it's pretty gross and should be avoided if possible.
Update
Now that you've provided more details about what you are trying to accomplish, I think I may have a better solution for you. You're right that structures do not support inheritance, but what they do support is interfaces. So, if all you need is a bunch of range types, one per value-type, all having the same minimum and maximum properties, but all returning different predetermined values, then you could do something like this:
Private Interface IRangeValueType(Of T)
ReadOnly Property Minimum As T
ReadOnly Property Maximum As T
End Interface
Private Structure RangeInt64
Implements IRangeValueType(Of Int64)
Public ReadOnly Property Minimum As Long Implements IRangeValueType(Of Int64).Minimum
Get
Return 100
End Get
End Property
Public ReadOnly Property Maximum As Long Implements IRangeValueType(Of Int64).Maximum
Get
Return 200
End Get
End Property
End Structure

How to create a list of multiple object types and preserve methods/properties?

I have a program that de-serializes stuff from an xml file and does all kinds of fancy things with it. I have 2 arrays in the XML file, one called variables and one called lookupTables. I also have 2 classes, variable and lookupTable. Both of those classes inherit from a class called definition. definition is inherit only and has one method that must be inherited, evaluate. Here is the code:
Definition
Public MustInherit Class Definition
Public Sub New()
End Sub
<XmlAttribute("name")> _
Public Property name As String
Public MustOverride Function evaluate(variables As Dictionary(Of String, Double)) As Double
End Class
Variable
<XmlRoot("variable")> _
Public Class Variable
Inherits Definition
<XmlAttribute("value")> _
Public Property value As String
Public Overrides Function evaluate(variables As Dictionary(Of String, Double)) As Double
Dim calculator As CalculationEngine = New CalculationEngine()
Return calculator.Calculate(value, variables)
End Function
End Class
LookupTable
<XmlRoot("lookupTable")> _
Public Class LookupTable
Inherits Definition
Public Sub New()
End Sub
<XmlElement("data")> _
Public Property data As Integer()()
Public Overrides Function evaluate(variables As Dictionary(Of String, Double)) As Double
Return True
End Function
End Class
My question is (hopefully) very simple. How can I create a list of Defintions (so a list containing both Variables and LookupTables) without loosing their individual methods and properties. All I will need to use this list for is calling evaluate.
I thought I could just create a List(Of Definition) since both Variable and LookupTable are guaranteed to implement evaluate() but as I read, it seems that typecasting both of the lists would strip them of their own innards and keep onluy what is common with Definition. What can I do here?
Since both your objects inherit from definition, you could create a list of Definition items then when you need to access specific methods, you cast them to their proper type using directCast to their specific type. To determine the type, you can use
If you had multiple variables types not inheriting from the same base, you could create a list of objects and apply the same idea.
'List of definition item
Private _List As New List(Of Definition)
'When you want to use specific method, you can cast items back to their types.
For Each Item As Definition In _List
Select Case Item.GetType
Case GetType(LookupTables)
Dim Table As LookupTables = DirectCast(Item, LookupTables)
Table.msg() 'Method in my LookupTables class only.
Case GetType(Variables)
Dim Variable As Variables = DirectCast(Item, Variables)
Variable.WriteToConsole() 'Method found in Variables class only.
End Select
Next
As for casting,
you can cast your LookupType to definition and vice-versa to use their respective methods as needed.
The simple answer was to use an ArrayList.

How to mimic Java's Wildcard types in VB.net?

I have an interface which I defined like this:
Public Interface ISomething(Of T)
' methods
End Interface
I now did an implementation:
Public Class ConcreteThing
Implements ISomething(of SomeClass)
' Implementation
End Class
I have multiple such concrete implementations, and want to have a function which returns any of them based on its parameters. In Java, I would do something like this:
public ISomething<?> getSomething(ParamType p) {
if(p.hasFoo()) return new ConcreteThing();
if(p.hasBar()) return new OtherConcreteThing();
throw new IllegalStateException("p neither has Foo nor Bar");
}
I already searched about this issue and found out that VB.net does not have wildcard types, so I tried:
Public Function GetSomething(p as ParamType) as ISomething(Of Object)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
This compiles, but I get the warning: Runtime errors might occurr when converting 'Foo.ConcreteThing' to 'Foo.ISomething(Of Object)'.
When I try the following, as suggested in a similar question:
Public Function GetSomething(Of T)(p as ParamType) as ISomething(Of T)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
the warning only changes to Runtime errors might occurr when converting 'Foo.ConcreteThing' to 'Foo.ISomething(Of T)'.
So, how do I get this right? Or, if this indeed IS right, how do I have Visual Studio ignore this warning?
I investigated on this issue a little more, discussed it with my colleagues, and I think I found the solution / reason for the warnings.
The warning message is a bit hard to understand and unconcise. What they are trying to say is that, as silly as it sounds, covariance does not work as expected for primitive types, even when using the Out keyword!
Consider an excerpt from this example on MSDN:
' Covariance.
Dim strings As IEnumerable(Of String) = New List(Of String)()
' An object that is instantiated with a more derived type argument
' is assigned to an object instantiated with a less derived type argument.
' Assignment compatibility is preserved.
Dim objects As IEnumerable(Of Object) = strings
This works. Now, change the first IEnumerable to IList:
Dim strings As IList(Of String) = New List(Of String)()
Dim objects As IEnumerable(Of Object) = strings
Works, too. OK, we are lucky, let's change the second:
Dim strings As IList(Of String) = New List(Of String)()
Dim objects As IList(Of Object) = strings
Boom, InvalidCastException. Looking at the signature, this is because the generic parameter in IEnumerable is defined as Of Out T, and IList is only defined As T.
Now, let's define our own.
Interface ISomething(Of Out T)
ReadOnly Property Value As T
End Interface
Class IntThing
Implements ISomething(Of Integer)
Public ReadOnly Property Value As Integer Implements ISomething(Of Integer).Value
Get
Return 42
End Get
End Property
End Class
Now, do this:
Dim s1 As ISomething(Of Integer) = new IntThing()
Works. Now add this:
Dim s2 As ISomething(Of Object) = s1
Boom, InvalidCastException. Now, the funniest part. Add a second implementation of ISomething:
Class StringThing
Implements ISomething(Of String)
Public ReadOnly Property Value As String Implements ISomething(Of String).Value
Get
Return "foo"
End Get
End Property
End Class
And do:
Dim s1 As ISomething(Of String) = New StringThing()
Dim s2 As ISomething(Of Object) = s1
This, on the other hand, works! So, let's go back to the List example.
Dim ints As IEnumerable(Of Integer) = New List(Of Integer)()
Dim objects As IEnumerable(Of Object) = ints
This will get you an InvalidCastException, too.
So, my conclusion is that covariance not only needs the Out keyword, it additionally only works with non-primitive types. .net seems to handle wrapper classes differently to the JVM.
So, never ignore this warning when it pops up. When it does, things will go wonky in an absolutely illogical way! That means, for what I want to achieve, going with simple Objects instead trying to find an equivalent for ISomething<?> is the way to go.
I only use this internally to read a binary file into a more convenient structure to extract the data I pass out via the API in the end, so using Object does not make things very much worse here.
It's weird, I don't get the warning like you do. But I do get an InvalidCastException if I try to run the code.
To get rid of the error (and hopefully your warning as well), you can make the generic type T on ISomething covariant.
Public Interface ISomething(Of Out T) ' Add the "Out" keyword here to make it covariant
' methods
End Interface
Then you should be able to use your GetSomething function as you had attempted:
Public Function GetSomething(p as ParamType) as ISomething(Of Object)
If p.HasFoo Then Return New ConcreteThing()
If p.HasBar Then Return New OtherConcreteThing()
Throw New InvalidOperationException("p neither has Foo nor Bar")
End Function
Relevant documentation: Covariance and Contravariance in Generics
Covariance
Enables you to use a more specific type than originally specified.
You can assign an instance of IEnumerable<Derived> (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable<Base>.
And lower in the Defining Variant Generic Interfaces and Delegates section:
A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler).

So a VB interface can't have shared functions. Is there an alternative to creating dummy objects?

To avoid getting into the weeds on my particular program, let me just create a simplified case.
I have a generic class that should work on a variety of objects. Each of those objects must implement a certain interface.
What I WANT to say is something like:
Public Interface GenThing
Shared Function thing_name() As String ' This doesn't work! Can't be shared!
Sub FillOne(row As DataRow)
End Interface
public class Thing1
implements GenThing
public shared function thing_name() as string implements GenThing.thing_name
return "thing number one"
end function
public sub FillOne(row as DataRow) implements GenThing.MakeOne
... bunch of work ...
end sub
end class
public class ThingUtil(of T as {GenThing,New})
public function GetList(id as integer) as List(of T)
dim name=T.thing_name() ' This doesn't work!
dim ds as DataSet=GetData(name,id) ' bunch of work here that's the whole point of the class but not relevant to the question
dim my_list = new List(of T)
for each row as DataRow in ds.tables(0).rows
dim my_t = new T()
my_t.FillOne(row)
my_list.add(my_t)
next
return my_list
end function
end class
Do you get my problem? I need every class that implements the interface to have a function that returns a "name" that is used to get the data that is needed to create an instance of the object. But I need to know this name BEFORE I create the instance, because I need it to be able to create the instance. But VB doesn't allow an interface to have a shared function, so what I want to write doesn't work.
So what I've done is this:
I make thing_name not shared.
Then instead of simply "dim name=T.thing_name()", I write
dim dummy = new T()
dim name = dummy.thing_name()
Okay, it works, but it seems really ugly. I create an instance of the object, with all the overhead that that involves, just to get a piece of constant text.
Is there a better way? Or am I making a big deal out of nothing?
Update
I see that two people voted to close this question on the grounds that it is the same as "Why can't we have shared functions in an interface?"
I am not asking why I can't have a shared. I am saying, GIVEN that I can't, how do I solve this particular problem?
There's no really simple way of fixing this, no.
Depending on what thing_name does, however, you might approach things in a different way. If each implementation just returns a constant value, then it's effectively metadata about the class - and could be described in an attribute instead, which can be fetched at execution time. (See Type.GetCustomAttributes.) Unfortunately you can't then enforce all types implementing the interface to be decorated with the attribute - but you could write a unit test to check this pretty easily.
If thing_name needs to really do work at execution time, that's tougher. You could potentially look for a well-known shared method name instead and execute that via reflection (and again have unit tests to check that it's implemented properly).
I realize this is from a few years ago, but running into a similar problem, I wanted to offer a different solution. Pass a delegate as parameter to the ThingUtil constructor. You avoid having to put a shared method in an interface, and the constructor will force you to include the parameter at compile time.
You can add more delegates if needed, or to make it even simpler in this case, just pass name as a string instead of get_name as a delegate.
Define the delegate in the interface:
Public Interface GenThing
Delegate Function ThingNameDelegate() As String
Sub FillOne(row As DataRow)
End Interface
Public Class Thing1
Implements GenThing
Public Shared Function thing_name() As String 'name this whatever you want
Return "thing number one"
End Function
Public Sub FillOne(row As DataRow) Implements GenThing.FillOne
'do stuff
End Sub
End Class
In ThingUtil, add a member to store the delegate, a constructor parameter to to accept, and call it with .Invoke():
Public Class ThingUtil(Of T As {GenThing, New})
Private m_thing_name As GenThing.ThingNameDelegate
Public Sub New(thing_name As GenThing.ThingNameDelegate)
m_thing_name = thing_name
End Sub
Public Function GetList(id As Integer) As List(Of T)
Dim name = m_thing_name.Invoke()
Dim ds As DataSet = GetData(name, id) ' bunch of work here that's the whole point of the class but not relevant to the question
Dim my_list = New List(Of T)
For Each row As DataRow In ds.Tables(0).Rows
Dim my_t = New T()
my_t.FillOne(row)
my_list.Add(my_t)
Next
Return my_list
End Function
End Class
Finally, use it like this:
Dim tu as new ThingUtil(Of Thing1)(AddressOf Thing1.get_name)
tu.GetList(1)

why are overloaded private shared function not accessible when called from shared function in same class

Came across something I found interesting and would love an explanation.
Edit
This question is not meant to be answered with what should be done to fix it. I know the fixes. I want an explanation of why the compiler does what it does. Ex. Are the private functions not considered given this scenario?
Problem
I have a class that has a public shared(static) function called WhatIs. WhatIs takes a parameter that has a collection of objects. the code iterates over this collection and calls a WhatIs function that has a parameter matching type of what the object is.
When executed, an InvalidCastException exception is thrown because the execution is trying to call the WhatIs function that started this, not the one for the type provided.
That's weird, but what made it odd to me was when you change the private shared functions to public shared then it works fine.
Even odder, when you explicit cast the object then it works even if the function is private.
What?! someone please explain
Code
the guts:
Public Class House
Public Property Furniture As ICollection(Of Object)
Public Sub New()
Furniture = New List(Of Object)
End Sub
End Class
Public Class Chair
Public Property IsComfortable As Boolean
End Class
Public Class Table
Public Seats As Integer
End Class
Public Class HouseExaminer
Public Shared Function WhatIs(thing As House) As String
Dim isA As String = "a house that contains "
For Each item In thing.Furniture
isA &= WhatIs(item)
Next
Return isA
End Function
Private Shared Function WhatIs(thing As Chair) As String
Return "a " & If(thing.IsComfortable, "comfortable", "uncomfortable") & " chair "
End Function
Private Shared Function WhatIs(thing As Table) As String
Return "a table that seats " & thing.Seats & " iguanas"
End Function
End Class
to test
Imports System.Text
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports stuff
<TestClass()>
Public Class HouseExaminerTests
<TestMethod()>
Public Sub TestWhatIs()
Dim given As New House()
Dim expected As String
Dim actual As String
given.Furniture.Add(New Chair() With {.IsComfortable = True})
given.Furniture.Add(New Table() With {.Seats = 4})
expected = "a house that contains a comfortable chair a table that seats 4 iguanas"
actual = HouseExaminer.WhatIs(given)
Assert.Equals(expected, actual)
End Sub
End Class
result
debug the test and you get this:
InvalidCastException
Method invocation failed because 'Public Shared Function WhatIs(thing As stuff.House) As String' cannot be called with these arguments:
Argument matching parameter 'thing' cannot convert from 'Chair' to 'House'.
These changes make it work but why?!
make em public
change the private shared functions in HouseExaminer to public, rerun test. spoiler, it works
explicitly cast the objects
change them back to private then replace
isA &= WhatIs(item)
with
If TypeOf item Is Chair Then isA &= WhatIs(CType(item, Chair))
If TypeOf item Is Table Then isA &= WhatIs(CType(item, Table))
rerun test, and what do u know, it works
Firstly, it looks like you have implicit conversions turned on. That is the start of the issue. Secondly, you define Furniture as a List(of Object). Your first call to WhatIs is succeeding. The compiler is making a best guess as to which overload to use when passing what it sees as simply Object as it iterates through thing.Furniture, and it determines the public static version of the WhatIs method to be the most appropriate. It then attempts to implicitly convert Object to House, and inevitably fails.
Why does casting work? Because it takes the guess work out of determining which overload to use.
Moral of the story is: Don't make the compiler guess. Implicit conversion can lead to tricky bugs.
Edit: Why doesn't the compiler see the other overloaded functions?
The compiler has to determine the correct overload to use at compile time. It does not wait until runtime to determine which overload to use, and therefore doesn't have the luxury of inspecting the type of the object to determine the most appropriate overload.
Since the compiler only knows that furniture is a List(Of Object), technically (with implicit conversion turned on) all three of the overloads are deemed "appropriate," but the compiler must choose one. It ranks the possible overload candidates, and chooses the public version ahead of the private ones.
Use always
Option Strict On
You cannot make it more flexible by adding Methods equal in name, just with different parametertypes.
Update
Private Function ShowMe(data As Integer) As String
Return data.ToString
End Function
Private Function ShowMe(data As String) As String
Return data
End Function
Private Function ShowMe(data As Double) As String
Return data.ToString
End Function
Dim bla As New List(Of Object)
if you then call
bla.Add(12)
bla.Add("hi")
bla.Add(1.2)
Dim text As String
text = ShowMe(bla(0))
text = ShowMe(bla(1))
text = ShowMe(bla(2))
then the compiler will always complain that the correct method does not exist, because the correct method is not selected by checking the type, instead it is selected by the definition, for which type the container is defined for.
Private Function ShowMe(data As Object) As String
Return data.ToString
End Function
this would be called for all integer, doubles and strings. If it is not available, then some methods are used that can do some kind of automatic conversion. Thats why you can put an integer in a float, or put a number in a string.
One way would be to check for its type and do an explizit type conversion
For Each ele As Object In bla
If TypeOf ele Is Integer Then
text = ShowMe(CInt(ele))
ElseIf TypeOf ele Is Double Then
text = ShowMe(CDbl(ele))
Else
text = ShowMe(CStr(ele))
End If
Next
But this is still not so clean. If you want to access properties that all objects should support, then put them in a container and define the type as something that assures that those properties exist.