Assigning a 'type' to a variable at runtime

J

JohnR

I'm trying to find a way to create a variable of a given type at runtime
where I won't know the type until it actually executes. For example,

dim x as object = "hi"

x is declared as an object but x.gettype returns 'string', so it knows it
contains a string.

If I want to create a variable "y" as the same type that variable x contains
how would I do that without having to iterate thru every possible
type? That is, for the above example I would want the equivalent of "dim y
as string" because x.gettype is string. Another example:

dim x as object = new MyClass

x.gettype would return 'MyClass' so I would want the equivalent of "dim y
as myclass".

Although it's not legal to do this "Dim y as x.gettype.name" that is
exactly what I want to do.

Is there anyway to accomplish this?

Thanks, John
 
M

Mattias Sjögren

Although it's not legal to do this "Dim y as x.gettype.name" that is
exactly what I want to do.

Is there anyway to accomplish this?

No. Why do you think you need this? What will you do with the
variable? Why can't you simply use Object for the second variable as
well?


Mattias
 
C

Cor Ligthert [MVP]

JohnR,

We see this more in this newsgroup and than I think forever, what will be
the use of this solution. It sounds for me as throwing apples and pears in
one container and than split them again afterwards. Why not direct in two
containers. That will probably keep the taste of the apples and the pears
much better.

Can you explain to us what is your reason behind this question?

(That container withouth telling what it is, is of couse 'object').

Cor
 
H

Herfried K. Wagner [MVP]

JohnR said:
I'm trying to find a way to create a variable of a given type at runtime
[...]
Although it's not legal to do this "Dim y as x.gettype.name" that is
exactly what I want to do.

Strict typing is mainly a compile-time feature. This means that it will
prevent the developer from writing code which will crash at runtime. Thus
it doesn't make much sense to support a construct as shown above. You may
want to declare the variable 'As Object' and assign values/references of
arbitrary types at runtime.
 
P

Phill. W

JohnR said:
I'm trying to find a way to create a variable of a given type at runtime
where I won't know the type until it actually executes.

I would suggest that this is /possible/, but definitely not something
I would recommend - unless you *love* trying to sort out wierd
and wonderful Run-Time errors.

..Net is an odd mix of [what we used to call] Early and Late binding.
At compile time, it's "Early Bound", using strict Types for everything,
which means that you /have/ to know the Type of something before
you can compile code to do anything with it. Objects are nowhere
as useful as Variants used to be.
At run-time, though, .Net seems to fall back on something more akin
to "Late Binding", loading methods as and when it needs them.
dim x as object = "hi"

x is declared as an object but x.gettype returns 'string', so it knows it
contains a string.
True.

If I want to create a variable "y" as the same type that variable x
contains

If you don't know the Type of "x" to start with, how do you intend to
manipulate "y", whose Type you have to know before you can access
its properties and methods?

It boils down to having to know something about a class before you
can do anything with it.
how would I do that without having to iterate thru every possible
type?

You /could/ use Activator.CreateInstance, but it takes as one of
its arguments the Type of object you want to create ...

HTH,
Phill W.
 
J

JohnR

Thanks to all the replys... I understand that, at first glance, what I am
asking for doesn't make sense, but, it really does... I always start out
with the stating the problem as directly as possible without unnecessary
info, but since you all are asking "why in the world would you want to do
that?" here is why:

I am trying to write a new ArrayList class which will have (at least for my
application) a better IndexOf method. All through this forum we see
questions about people overriding the Equals method of a custom class only
to find that the ArrayList.Indexof method calls the Object.Equals method and
not their overridden Equals method. My goal was to remedy this situation.
In addition, I wanted to have IndexOf to do a case insensitive search if the
obj is of type 'string'. Here is the class def'n:

Public Class arraylist
Inherits System.collections.ArrayList
Public Shadows Function indexof(ByVal obj As Object) As Integer

'this will cause indexof to do a case insensitive search if obj
'is a string
If TypeOf obj Is String Then
For ptr As Integer = 0 To Me.Count - 1
If CType(Me(ptr), String).ToUpper = CType(obj,
String).ToUpper Then
Return ptr
End If
Next
Return -1
Else
For ptr As Integer = 0 To Me.Count - 1

'the next commented line won't work because it
'will call the object.equals method and NOT the
'overridden equals method of the class that is
'passed as the obj parameter

'If Me(ptr).equals(obj) Then

'However, let's say obj is of type "MyOwnClass" then
'the following WILL work because it will call the
'equals method that is defined in the MyOwnClass class.

If CType(Me(ptr), MyOwnClass).equals(obj) Then
Return ptr
End If

'taking this to the ultimate solution, I would have
'liked to do something like this:
'If Ctype(Me(ptr), Me(ptr).gettype.name).equals(obj) Then

Next
Return -1
End If

End Function
End Class

So you see, I only need to cast the type onto whatever is contained in the
obj so that it calls the proper Equals method. That's it. That's the only
reason I need to do this. I'm not going to mess with the obj in any other
way so I'm not worried about "bugs" that may be introduced by screwing with
variable types at runtime.
Clearly the alternative (and what I'm actually doing now) is testing the
type of obj for each of my custom classes, and doing a manual cast once I
find out what type it is. Very tacky, but it does work. I'm looking for a
more elegant, general solution here.

John

Phill. W said:
JohnR said:
I'm trying to find a way to create a variable of a given type at runtime
where I won't know the type until it actually executes.

I would suggest that this is /possible/, but definitely not something
I would recommend - unless you *love* trying to sort out wierd
and wonderful Run-Time errors.

.Net is an odd mix of [what we used to call] Early and Late binding.
At compile time, it's "Early Bound", using strict Types for everything,
which means that you /have/ to know the Type of something before
you can compile code to do anything with it. Objects are nowhere
as useful as Variants used to be.
At run-time, though, .Net seems to fall back on something more akin
to "Late Binding", loading methods as and when it needs them.
dim x as object = "hi"

x is declared as an object but x.gettype returns 'string', so it knows it
contains a string.
True.

If I want to create a variable "y" as the same type that variable x
contains

If you don't know the Type of "x" to start with, how do you intend to
manipulate "y", whose Type you have to know before you can access
its properties and methods?

It boils down to having to know something about a class before you
can do anything with it.
how would I do that without having to iterate thru every possible
type?

You /could/ use Activator.CreateInstance, but it takes as one of
its arguments the Type of object you want to create ...

HTH,
Phill W.
 
M

Mattias Sjögren

JOhn,
I understand that, at first glance, what I am
asking for doesn't make sense, but, it really does...

All through this forum we see
questions about people overriding the Equals method of a custom class only
to find that the ArrayList.Indexof method calls the Object.Equals method and
not their overridden Equals method.

Maybe I haven't been paying attention, but I don't see that asked very
often.

Anyway, Object.Equals is an Overridable method. As long as the Equals
method in your derived class is declared with Overrides, your
implementation should be called by ArrayList. This is basic
polymorphism.


Mattias
 
J

Jay B. Harlow [MVP - Outlook]

JohnR,
| All through this forum we see
| questions about people overriding the Equals method of a custom class only
| to find that the ArrayList.Indexof method calls the Object.Equals method
and
| not their overridden Equals method.

As Mattias suggests, and I believe we have discussed before Object.Equals is
overridable! If you *override* Object.Equals in your derived class (not
ArrayList). ArrayList.IndexOf will polymorphically call the "correct" equal
method, something like:

Public Class Thingamajig

Private ReadOnly m_value1 As String
Private ReadOnly m_value2 As Integer

Public Sub New(ByVal value1 As String, ByVal value2 As Integer)
m_value1 = value1
m_value2 = value2
End Sub

Public Overloads Function Equals(ByVal other As Thingamajig) As
Boolean
Return m_value1 = other.m_value1 AndAlso m_value2 =
other.m_value2
End Function

Public Overloads Overrides Function Equals(ByVal obj As Object) As
Boolean
If TypeOf obj Is Thingamajig Then
Return Equals(DirectCast(obj, Thingamajig))
Else
Return False
End If
End Function

End Class

Public Shared Sub Main()
Dim list As New ArrayList
list.Add(New Thingamajig("jay", 1))
list.Add(New Thingamajig("jay", 2))
list.Add(New Thingamajig("jay", 3))
list.Add(New Thingamajig("JohnR", 1))
list.Add(New Thingamajig("JohnR", 2))
list.Add(New Thingamajig("JohnR", 3))

Dim index As Integer = list.IndexOf(New Thingamajig("JohnR", 2))

End Sub



| Public Shadows Function indexof(ByVal obj As Object) As Integer
Shadows is anti-polymorphic!

Anti-polymorphic code normally causes more problems then it helps.

You need to *Override* IndexOf instead, something like:

| Public Overloads Overrides Function indexof(ByVal obj As Object) As
Integer

Overloads is needed here as IndexOf is overloaded (see below).



| 'this will cause indexof to do a case insensitive search if obj
| 'is a string
I would use a Case Insensitive Comparer, such as
System.Collections.CaseInsensitiveComparer.Default or DeafultInvariant
instead, something like:

Public Class ArrayList
Inherits System.collections.ArrayList

Public Overloads Overrides Function IndexOf(ByVal value As Object)
As Integer
Return IndexOf(value, 0, Me.Count)
End Function

Public Overloads Overrides Function IndexOf(ByVal value As Object,
ByVal startIndex As Integer) As Integer
Return IndexOf(value, startIndex, Me.Count - startIndex)
End Function

Public Overloads Overrides Function IndexOf(ByVal value As Object,
ByVal startIndex As Integer, ByVal count As Integer) As Integer
Dim comparer As IComparer =
CaseInsensitiveComparer.DefaultInvariant
For index As Integer = startIndex To startIndex + count - 1
If comparer.Compare(Me(index), value) = 0 Then
Return index
End If
Next
Return -1
End Function

End Class

The CaseInsensitiveComparer object knows how to do case insensitive
comparisons of strings & comparisons of other types (such as integers).

--
Hope this helps
Jay
T.S. Bradley - http://www.tsbradley.net


| Thanks to all the replys... I understand that, at first glance, what I am
| asking for doesn't make sense, but, it really does... I always start out
| with the stating the problem as directly as possible without unnecessary
| info, but since you all are asking "why in the world would you want to do
| that?" here is why:
|
| I am trying to write a new ArrayList class which will have (at least for
my
| application) a better IndexOf method. All through this forum we see
| questions about people overriding the Equals method of a custom class only
| to find that the ArrayList.Indexof method calls the Object.Equals method
and
| not their overridden Equals method. My goal was to remedy this situation.
| In addition, I wanted to have IndexOf to do a case insensitive search if
the
| obj is of type 'string'. Here is the class def'n:
|
| Public Class arraylist
| Inherits System.collections.ArrayList
| Public Shadows Function indexof(ByVal obj As Object) As Integer
|
| 'this will cause indexof to do a case insensitive search if obj
| 'is a string
| If TypeOf obj Is String Then
| For ptr As Integer = 0 To Me.Count - 1
| If CType(Me(ptr), String).ToUpper = CType(obj,
| String).ToUpper Then
| Return ptr
| End If
| Next
| Return -1
| Else
| For ptr As Integer = 0 To Me.Count - 1
|
| 'the next commented line won't work because it
| 'will call the object.equals method and NOT the
| 'overridden equals method of the class that is
| 'passed as the obj parameter
|
| 'If Me(ptr).equals(obj) Then
|
| 'However, let's say obj is of type "MyOwnClass" then
| 'the following WILL work because it will call the
| 'equals method that is defined in the MyOwnClass class.
|
| If CType(Me(ptr), MyOwnClass).equals(obj) Then
| Return ptr
| End If
|
| 'taking this to the ultimate solution, I would have
| 'liked to do something like this:
| 'If Ctype(Me(ptr), Me(ptr).gettype.name).equals(obj) Then
|
| Next
| Return -1
| End If
|
| End Function
| End Class
|
| So you see, I only need to cast the type onto whatever is contained in the
| obj so that it calls the proper Equals method. That's it. That's the
only
| reason I need to do this. I'm not going to mess with the obj in any other
| way so I'm not worried about "bugs" that may be introduced by screwing
with
| variable types at runtime.
| Clearly the alternative (and what I'm actually doing now) is testing the
| type of obj for each of my custom classes, and doing a manual cast once I
| find out what type it is. Very tacky, but it does work. I'm looking for
a
| more elegant, general solution here.
|
| John
|
| | > | >> I'm trying to find a way to create a variable of a given type at
runtime
| >> where I won't know the type until it actually executes.
| >
| > I would suggest that this is /possible/, but definitely not something
| > I would recommend - unless you *love* trying to sort out wierd
| > and wonderful Run-Time errors.
| >
| > .Net is an odd mix of [what we used to call] Early and Late binding.
| > At compile time, it's "Early Bound", using strict Types for everything,
| > which means that you /have/ to know the Type of something before
| > you can compile code to do anything with it. Objects are nowhere
| > as useful as Variants used to be.
| > At run-time, though, .Net seems to fall back on something more akin
| > to "Late Binding", loading methods as and when it needs them.
| >
| >> dim x as object = "hi"
| >>
| >> x is declared as an object but x.gettype returns 'string', so it knows
it
| >> contains a string.
| >
| > True.
| >
| >> If I want to create a variable "y" as the same type that variable x
| >> contains
| >
| > If you don't know the Type of "x" to start with, how do you intend to
| > manipulate "y", whose Type you have to know before you can access
| > its properties and methods?
| >
| > It boils down to having to know something about a class before you
| > can do anything with it.
| >
| >> how would I do that without having to iterate thru every possible
| >> type?
| >
| > You /could/ use Activator.CreateInstance, but it takes as one of
| > its arguments the Type of object you want to create ...
| >
| > HTH,
| > Phill W.
| >
| >
|
|
 
J

JohnR

Hi Jay,

First thank you for your most excellent suggestion of using Icomparer for a
case insensitive search. I didn't even think of that one!

However, concerning the overrideable object.equals method... I must be
really missing something, cause it doesn't work for me. Let me explain that
I override the equals method because that way I can compare equality using
different criteria. Below is a complete example that you can cut and past
into a forms' code. It consists of a custom class called PERSON with two
properties. IsMale as string, and Age as integer. I also override the
equals method to determine equality if the age matches. I store instances of
the People class in an arraylist called PeopleCollection. I can pass
either an instance of the People class to the PeopleCollection.indexof
method or I can pass an integer. Either way I would compare the ages.
The problem is that in this code my overridden equals method never gets
called. If you can explain why my code doesn't work that would be great.
I have actually gotten this stuff to work by creating a new arraylist class
that inherits system.collection.arraylist. In my arraylist class I override
the indexof method and simply interate thru the if me.item(i).equals(obj)
for each of the items in the arraylist. In my arraylist class the proper
equals method DOES get called, so it is a good workaround for me. I'm just
not sure why the 'real' arraylist indexof function doesn't call the right
equals method.... Anyway when I run the following code on my system, the
overridden equals method in the Person class never gets called.


Option Strict On
Option Explicit On

Public Class Form1

Inherits System.Windows.Forms.Form

'insert your windows generated code here

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load


Dim PeopleCollection As New ArrayList

Dim Customer As New Person

Customer.Age = 25

Customer.IsMale = "Yes"

PeopleCollection.Add(Customer)

Dim y As New Person

y.Age = 25

Dim x As Integer = PeopleCollection.IndexOf(y) 'this returns -1

End Sub

End Class

Public Class Person

Private _IsMale As String

Private _age As Integer

Public Overloads Overrides Function equals(ByVal obj As Object) As Boolean

If obj Is Nothing Then Return False

If Me.GetType Is obj.GetType Then

Return Me.Age = CType(obj, Person).Age

ElseIf TypeOf obj Is Integer Then

Return Me.Age = CType(obj, Integer)

End If

End Function

Public Overloads Function equals(ByVal obj As Person) As Boolean

If Me.Age = obj.Age Then

Return True

End If

Return False

End Function

Public Property IsMale() As String

Get

Return _IsMale

End Get

Set(ByVal Value As String)

_IsMale = Value

End Set

End Property

Public Property Age() As Integer

Get

Return _age

End Get

Set(ByVal Value As Integer)

_age = Value

End Set

End Property

End Class
 
L

Larry Lard

JohnR wrote:
[snip]
I'm just
not sure why the 'real' arraylist indexof function doesn't call the right
equals method.... Anyway when I run the following code on my system, the
overridden equals method in the Person class never gets called.

I just copied and pasted your code into a brand new project ....
Dim x As Integer = PeopleCollection.IndexOf(y) 'this returns -1

.... and x got set to zero, after hitting a breakpoint I set in
Person.equals ... so if you are getting something else I am at a loss
as to why.
 
J

Jay B. Harlow [MVP - Outlook]

JohnR,
| I'm just
| not sure why the 'real' arraylist indexof function doesn't call the right
| equals method.... Anyway when I run the following code on my system, the
| overridden equals method in the Person class never gets called.
The override Person.Equals(Object) *is* called!

The overload Person.Equals(Person) is not called, which is why I normally
call Person.Equals(Person) in my Person.Equals(Object) overload.
As I showed earlier, I would use TypeOf to check the type rather then
GetType.

Public Overloads Overrides Function Equals(ByVal obj As Object) As
Boolean
If obj Is Nothing Then Return False
If TypeOf obj Is Person Then
Return Equals(DirectCast(obj, Person))
ElseIf TypeOf obj Is Integer Then
' HACK: defining behavior inconsistent with the framework!
Return Me.Age = DirectCast(obj, Integer)
End If
End Function

Person.Equals(Person) is used when your code has a Person variable & you
call Equals on it with another Person variable.

Dim customer As Person
Dim anotherPerson As Person
' Calls Person.Equals(Person)
If customer.Equals(anotherPerson) Then
...
End If

In VS 2005 (.NET 2.0) I would implement IEquatable(Of T) to get
Person.Equals(Person) (see below for sample):
http://msdn2.microsoft.com/en-us/library/ms131187


Also "overloading" Equals, to compare Persons to Integers is *NOT*
advisable, as Object.Equals is defined to be symmetric. That is x.Equals(y)
returns the same value as y.Equals(x).

http://msdn.microsoft.com/library/d...f/html/frlrfsystemobjectclassequalstopic1.asp

Dim x As Object = New Person
Dim y As Object = 100

Debug.Assert(x.Equals(y) = y.Equals(x))

Fails as System.Integer cannot compare itself to a Person.


I've discussed this, I believe with you, in this group before. See the
thread titled "Overriding Equals method not being called when doing IndexOf
an item in an ArrayList" from April 26 2005.

http://groups.google.com/group/micr...1fc8fdc7cfd/88a682c0252de224#88a682c0252de224

Be certain to review the above thread it has a lot of sage advice on this
matter...


FWIW: In VS 2005 (.NET 2.0) my person class would look something like:

' VS.NET 2005 syntax (from memory, no syntax checking)
Public Class Person
Implements IEquatable(Of Person)

... other stuff ...

#Region " Equatable support "

Public Overloads Overrides Function Equals(ByVal obj As Object) As
Boolean
If TypeOf obj Is Person Then
Return Equals(DirectCast(obj, Person)
Else
Return False
End If
End Function

Public OverLoads Function Equals(ByVal other As Person) As Boolean _
Implements IEquatable(Of Person).Equals
Return Me... = other... AndAlso ...
End Function

Public Overloads Shared Operator =(ByVal x As Person, ByVal y As
Person) As Boolean
' TODO: Check for null parameters
Return x.Equals(y)
End Operator

Public Overloads Shared Operator <>(ByVal x As Person, ByVal y As
Person) As Boolean
' TODO: Check for null parameters
Return Not x.Equals(y)
End Operator

#End Region

End Class

Notice that Equals(Person) does all the "heavy lifting", that the other
flavors of "equality" (Equals(Object) & operators) are defined in terms of
it.

--
Hope this helps
Jay
T.S. Bradley - http://www.tsbradley.net


| Hi Jay,
|
| First thank you for your most excellent suggestion of using Icomparer for
a
| case insensitive search. I didn't even think of that one!
|
| However, concerning the overrideable object.equals method... I must be
| really missing something, cause it doesn't work for me. Let me explain
that
| I override the equals method because that way I can compare equality using
| different criteria. Below is a complete example that you can cut and past
| into a forms' code. It consists of a custom class called PERSON with two
| properties. IsMale as string, and Age as integer. I also override the
| equals method to determine equality if the age matches. I store instances
of
| the People class in an arraylist called PeopleCollection. I can pass
| either an instance of the People class to the PeopleCollection.indexof
| method or I can pass an integer. Either way I would compare the ages.
| The problem is that in this code my overridden equals method never gets
| called. If you can explain why my code doesn't work that would be great.
| I have actually gotten this stuff to work by creating a new arraylist
class
| that inherits system.collection.arraylist. In my arraylist class I
override
| the indexof method and simply interate thru the if me.item(i).equals(obj)
| for each of the items in the arraylist. In my arraylist class the proper
| equals method DOES get called, so it is a good workaround for me. I'm
just
| not sure why the 'real' arraylist indexof function doesn't call the right
| equals method.... Anyway when I run the following code on my system, the
| overridden equals method in the Person class never gets called.
|
|
<<snip>>
 
J

JohnR

Hi Larry and Jay.
First, you guys are great for taking the time to work with me to sort this
out. I REALLY appreciate it. In the end maybe we all will learn something!

I did some more experimenting and this is what I found... First, my sample
project must have been somehow corrupt because, as you Larry said, when I
posted my own code into a NEW project the Equals method DID get called (this
type of thing could cause one to drink to excess!)

Some observations about the sample I gave: Using the regular arraylist (as
I do in the sample code) if I pass an instance of my custom class then it
does, indeed, call the overridden equals defined in the custom class. This
is what I would expect. If I pass an integer as the parameter of the
indexof(int) instead of an instance of the class, my custom equals DOES NOT
get called (again, what I expected). You are correct, Jay, we did discuss
this some time ago. My apparently corrupt project threw me into a loop
again when it didn't work and I thought I was missing something again.
Thanks for you patience.

Here's what I infer about the operation of the standard ArrayList.Indexof
method. If you pass as a parameter anything other than what is in the
arraylist you can never have a symetrical relationship (as Jay pointed out).
That is x.equals(y) will never be y.equals(x). So the standard IndexOf
will automatically return -1 (false). Now here comes the controversial
part (at least according to Jay :) ). I know that Microsoft states that the
equals method must be symetrical however I have a requirement that it not
be. Here is why. In my application I have many custom classes that are
stored as collections in an 'arraylist'. These arraylist collections are
being searched constantly for particular instances of the class. For
example, I might have a PERSON class that has properties of EmployeeNumber
and SocialSecurity Number, along with 15 other misc properties about the
person. Both of these properties will uniquely identify the person, so I
can use either one to find the correct person. Using the standard IndexOf
I would have to load either the Emp# or the SS# into a new Person instance
and pass that instance to the IndexOf method. Using a custom Arraylist
class that overrides the IndexOf method to call the Equals method all the
time (even if the objects being compared are of different types) I can do
the appropriate compare in my custom Equals method. Bottom line is that the
main code becomes a little simpler.
FoundPerson = PersonArraylist.Indexof(1234)
instead of:
x = new person
x.empno = 1234
FoundPerson = PersonArraylist.Indexof(x)

I know that my way has some limitations (if empno and ss# are both integers,
and you pass an integer how do you know what you are comparing to?) and
these are valid points. However, I created this code at the very beginning
of the project (when I was first learning VB.Net and OOP) and didn't have
the complete picture. Would I do it differently today.... probably yes.
Will I go back and tear out all my working code and modify it. Not sure
yet....

Well, thats my story... Thanks again to both of you. I've been doing this
stuff now for 35 years (even though I still feel like I'm only 35 years
old!!) and it's clear that you guys love this as much as I do. I really
enjoyed having this "back and forth" with you. As I'm still learning, we
probably will have the opportunity to do it again sometime...
Regards, John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top