Passing Arrays by Reference Errors Type Cannot be Inferred

Element6

Well-known member
Joined
Feb 16, 2010
Messages
85
Programming Experience
5-10
Ok this is new.

VB.NET:
Public Sub AddToArray(ByRef ArrayOf() As Object, ByVal Obj As Object) 
            If ArrayOf Is Nothing Then
                ReDim ArrayOf(0)
            Else
                ReDim Preserve ArrayOf(ArrayOf.Length)
            End If

            ArrayOf(ArrayOf.Length - 1) = Obj
    End sub

Very simple code right? Problem is if my Array is derived from a Non .NET type say someClassA it can't infer the data type. Why does it treat objects as a unique type other then a generic?

VB.NET:
Dim MyArray() of SomeClassA
Dim ANewObj of SomeClassA
.
. Do something to ANewObj
.
AddToArray(MyArray, ANewObj)

Gives me an error. TypeMismatch via Objects?
 
Ok I'm stumped; this works but the above code doesn't? Any ideas why?

VB.NET:
Module module1

    Public Class b
        Public valueb As Integer = Rnd() * 10 + 1
    End Class

    Public Class a
        Inherits b
        Public value As Integer = (Rnd() * 100) + 11
        Public value2 As Integer


        Sub New()
            value2 = valueb
        End Sub
    End Class


    Sub Main()
        Dim i As Integer

        Dim firstArray(3) As a
        Dim firstArrayCopy() As a
        Dim secondArray(3) As a
        Dim secondArrayCopy() As a

        For x = 0 To 3
            firstArray(x) = New a
            secondArray(x) = New a
        Next
        firstArrayCopy = firstArray
        secondArrayCopy = secondArray

        For i = 0 To firstArray.GetUpperBound(0)
            Console.Write(firstArray(i).value.ToString & " ")
        Next

        FirstDouble(firstArray)

        For i = 0 To firstArray.GetUpperBound(0)
            Console.Write(firstArray(i).value.ToString & " ")
        Next

        If firstArray Is firstArrayCopy Then
            Console.WriteLine("The references are equal.")
        Else
            Console.WriteLine("The references are not equal.")
        End If



        For i = 0 To secondArray.GetUpperBound(0)
            Console.Write(secondArray(i).value.ToString & " ")
        Next

        SecondDouble(secondArray)

        For i = 0 To secondArray.GetUpperBound(0)
            Console.Write(secondArray(i).value.ToString & " ")
        Next

        If secondArray Is secondArrayCopy Then
            Console.WriteLine("The references are equal.")
        Else
            Console.WriteLine("The references are not equal.")
        End If

    End Sub ' Main

    Sub FirstDouble(ByVal t1array() As Object)
        Dim i As Integer
        Dim t1aArray() = t1array

        For i = 0 To t1array.GetUpperBound(0)
            t1array(i).value = t1array(i).value * 2
        Next

        t1array = t1aArray.Clone
        't1array = New Integer() {11, 12, 13}
    End Sub

    Sub SecondDouble(ByRef t2array() As Object)
        Dim i As Integer
        Dim t2aArray() = t2array

        For i = 0 To t2array.GetUpperBound(0)
            t2aArray(i).value = t2aArray(i).value * 3
        Next

        t2array = t2aArray.Clone
        't2array = New Integer() {11, 12, 13}
    End Sub

End Module

Can anyone help with this? My implementation for the first code is :

VB.NET:
AddToArray(AnArrayOf, New SomeClassA)

it executes the code; but does not allow the return; I receive.
A first chance exception of type 'System.InvalidCastException' occurred in MySystem.exe
 
Last edited:
You should be writing that method using generics:
VB.NET:
Public Sub AddToArray(Of T)(ByRef array As T(), ByVal element As T)
    If array Is Nothing Then
        array = New T() {element}
    Else
        System.Array.Resize(array, array.Length + 1)
        array(array.GetUpperBound(0)) = element
    End If
End Sub
As far as why you had issues, consider the fact that you're declaring your first parameter as type Object() and using ReDim in the method. That's going to create an Object array, yet the argument you pass in is type SomeClassA(), so how does that work? You create an Object() in the method and expect that to get assigned to a SomeClassA() variable when the method completes.
 
I always thought that Object was a generic, so my assumption was that the reference of the array would be passed and all the derived Types. Which is logical enough.

ByRef says that it passes the Reference to the Array not the Value; so I naturally assumed that the Type data would be derived also as a matter of viewing the reference.

My code :
VB.NET:
   Public Sub AddToArray(ByRef ArrayOf() As Object, ByVal Obj As Object) 
            If ArrayOf Is Nothing Then
                ReDim ArrayOf(0)
            Else
                ReDim Preserve ArrayOf(ArrayOf.Length)
            End If

            ArrayOf(ArrayOf.Length - 1) = Obj
    End sub

Your code:
VB.NET:
Public Sub AddToArray(Of T)(ByRef array As T(), ByVal element As T)
    If array Is Nothing Then
        array = New T() {element}
    Else
        System.Array.Resize(array, array.Length + 1)
        array(array.GetUpperBound(0)) = element
    End If
End Sub

Comparing the two I see little difference; other then the generic passing which is .NET specific and T auto reference identifies the underline base type; which is what I thought Object did. Are you telling me VB.NET treats Object as a type and not a generic? That would be contray to every other language including Java and C++.

Thats a .NETism; What special constructor does Object type have that uniquely identifies the base type? The whole purpose of the Object Keyword is to define a "Generic Object" base I don't understand what Microsoft thinks they are doing other then over complicating a very simple implementation by describing an object as anything other then a pointer to a reference.
 
I think you need to do some reading on what the term "generic" means in this specific context. .NET generics are pretty much just like Java generics, so your assertion that Microsoft are somehow corrupting something that is simple elsewhere is misdirected. In .NET programming the term "generic" has a specific meaning beyond its regular English language meaning.
 
Generic programming - Wikipedia, the free encyclopedia

I used the term correctly, please don't make this into a grammer conversation.

For the record Generics are none specific typed; until which time they are required to be typed and are not new to programming as you can read in the article they have been around since the early 80's 1983 as the documentation sited.

In this instance, OBJECT the syntax keyword is generally referred to in almost every language as a generic; the type is deferred until the object is accessed and then it is qualified. The specific terminology for this method or pattern is Late Binding. Late binding is not new, it is relatively old; I was doing late binding in the early 90's in pascal.

My question was specific in the nature of, what is the difference between the .NET view of Object and the "T" Keyword Generic? In every language from JAVA to C++ Object is a reserved word which specifically denotes a generic reference to some arbitrary class. Generally, in the linker the code is set to a pointer and the pointer is the accessor; it simply points to the object, when the object is returned it reports it's type and the type reference is established.


My question is "Why is .NET treating Object as anything other then this standard convention is there a standard deviation which suggests that it is more applicable to establish some sort of new convention which is against the grain?"


and it is not like JAVA it's more like a mix between C++ and some weird way of handling class memory. Java would just pass the reference and do polymorphism on the way out. This is a bad construct and attempting to force programmers to view the world from the C++ point of view with managed overhead. Which is not valid in most cases; developers do not code normally for 1 type of system it's normally adhoc and cross platform. That argument is way to large in scope and I think Microsoft is shooting themselves in the foot here.

C++ handles Arrays in 3 formats REFERENCE implicit REFERENCE deferred and VALUE.

In VB referencing is always implicit, and in JAVA. It's never deferred - and never needs to be - it's just a simple pass if you want a local copy or "clone" you slice the array. Deferring a reference is a shallow view of a universe from a managed state; and in framework development noone cares about the managed state. You just pass the reference; and it is handled by the origionator all that stuff is a matter of how the source is treating it.

Personally, I think it's a stupid view, for a simple problem and overly complex. Most developers (good ones) dont do casting it's not required except to string or to decimal or back and forth the ones who do a lot of casting, are the ones that didn't handle the problem in the right place to begin with "the data source".

I am not happy with not being able to simple pass an object as a calculated pointer; PC's are NOT MAC's, I like to tinker with my PC and I don't need the managed overhead. It's exactly why I write my own OS and I defer all the Microsoft "specifics" - it's useless if I wanted an apple. I would have bought one I bought a PC for the reason of being able to futz with it. PC's are not appliances, they are not toasters - they are hobbiest toys. "Toasters" are macs and other useless devices that only do 1 thing very well.
 
Last edited:
Anyway, Object is the root base class in the .NET Framework, so Object references are "generic" in so far as every object is an Object, courtesy of every type being derived from Object, and thus an Object reference can refer to any object. That has been the case from .NET 1.0, well before the concept of generic types and members was introduced in .NET 2.0. .NET generics work in quite a different way to the Object type.

In your case, your parameter is type Object(). The first thing to note is that it is NOT type Object, but rather type Object(), i.e. an array of Object references. If you use ReDim to create an array inside the method then you are creating an array of Object references, i.e. an array whose elements can be any type.

Once the method returns, that array has to be assigned to the original argument, i.e. a variable whose type is SomeClassA(), i.e. an array whose elements must be type SomeClassA. How can an array object whose elements can be anything be assigned to a variable of a type that is an array whose elements must be type SomeClassA? The answer is that it can't. It wouldn't make sense to do so in a stringly typed language like VB and the compiler won't let you, as it told you.

The difference with true generics is that while they are designed to be able to be used with any type, when you actually use them you have to choose a type and stick to it. While you could declare a variable of type Object and then assign a thousand different objects to it over time, all of different types, with generics you must specify the generic type when you declare the variable and you then have to stick to that type. You can't just declare a generic List, for example, and then assign Lists with different item types to it. When you declare a List you have to set the generic type, e.g. List(Of String), and then you have to stick to that type. Object is more "general" in that it can refer to any object of any type at any time. Generics, on the other hand, can be used with any type but any one instance must fix that type and stick to it.
 
Ok, let me clarify what you just wrote, because I feel stupid here or I didn't express the origional question correctly.

When declaring an Array as a ByRef pass; Array's are the principal type not the type association correct?

In your case, your parameter is type Object(). The first thing to note is that it is NOT type Object, but rather type Object(), i.e. an array of Object references. If you use ReDim to create an array inside the method then you are creating an array of Object references, i.e. an array whose elements can be any type.

Reitterated :
... i.e. an array whose elements can be any type.

*BLINK* *BLINK* an Array is the construct? That is EXACTLY the intent that coded for.

... Once the method returns, that array has to be assigned to the original argument, i.e. a variable whose type is SomeClassA(), i.e. an array whose elements must be type SomeClassA. ...

I am saying this is the ERROR in logic. No it doesn't need to be "assigned to the original argument" it IS the orgional arguement "ByRef" the ByVal pass of the typed SomeClassA as Generic Object.

This statement is contrary to the above statement since we know two things. The Array is a Reference Pass not a Value, which has typed association; and the objects associated to the array are of "any specific type" in this case : "SomeClassA".

This is a compiler ERROR; the linker knows that the Array being passed is of Object; that the Value being assigned is Object. It also knows that the derived class of the Assigned Object is "SomeClassA", what the array is doesn't matter it's an Array.

So my origional logic is still valid, the linker knew the reference, and it knew the baseline type associations. That is why I am sitting here going umm? *BLINK BLINK*



Here is my clarifying example.
What if I had an Array of Multiple Types? Such as :

VB.NET:
Dim thisArray() as Array

thisArray(0) = New SomeClassA()
thisArray(1) = New SomeClassB()
thisArray(2) = New SomeClassC()
thisArray(3) = New SomeClassD()
thisArray(4) = New SomeClassE()

The difference with true generics is that while they are designed to be able to be used with any type, when you actually use them you have to choose a type and stick to it.

What then? No I disagree whole heartly; Generics are just that "abstract" declarations that are handled on the fly during the need and at different timing intervals.



1. Rediming the array simply states. Redim of nothing; make a place holder doesn't even need to be an object. Use Nothing to create the placement.

2. Adding the Object reference is the next step; so it does it as "Object" generic which is derived from "SomeClassA" (technically IS SomeClassA with a Object generic wrapper).

It leaves the routine and error's saying that the cast is invalid? it's a Generic Object which is implicitly an object of SomeClassA. I am still not understanding why the code isn't working.


You never answered the Question.

What is the difference between Object and T associations in VB.NET?
Is T just a generic way of looking up some Type information and assigning it locally implicitly and if so why doesn't object do the same thing because that IS exactly what Object is whats the difference?
 
You obviously don't know how generics work in .NET so you really need to do some reading on that. The term "generic" has a specific meaning in .NET programming that is based on its general meaning in the English language but applies to specific functionality in the .NET Framework. The Object class has been part of the Framework since .NET 1.0. Generics were only added in .NET 2.0. That alone should tell you that generics are something special, above and beyond what the word "generic" means in the English language.

The Object class could be considered generic in the sense that it can refer to an object of any type but it has NOTHING to do with .NET generics. Object and T are COMPLETELY different things. Object is a type, while T is a generic type parameter. There is no such type as T. T stands for a type that you specify at run time.

Consider the ArrayList class and the generic List(Of T) class. The ArrayList has been around since .NET 1.0. It is essentially a dynamic array, but one of the main problems with the ArrayList class was that it it could store items of any type. It's Add method has a parameter of type Object and its Item property is type Object. Now, let's say that you want a dynamic array of Strings. If you use an ArrayList, there's no way for you to enforce that all items are Strings without writing code to validate each item before adding it. Also, when you retrieve an item from the ArrayList you get it as an Object reference, meaning that you have to cast it as type String in order to use it as a String. If it isn't a String, which it might not be because any object could have been added, then that cast will fail.

Now, with the advent of .NET 2.0 and the addition of generics, the List(Of T) class can overcome those issues. T is not a type itself, but rather a place-holder for any type that you care to specify. The thing is, you MUST specify that type and, once you do, you must stick to it. The List(Of T) class also has an Add method with a parameter of type T and its Item property is also type T. Now, when you create a generic List, you have to decide what type T is going to be. Following on from the example above, you can create a List(Of String) and, as soon as you do that, the Add method's parameter is fixed as type String and so is the Item property. You now have a dynamic array that will only accept Strings, which is enforced by the compiler, and it also returns String references, so no casting is needed when retrieving items.

You can also create a List(Of Integer) that will only store Integers, a List(Of Form) that will only store forms, etc, etc. You could also create a List(Of Object) and it would behave exactly as the ArrayList does. So, while a generic class can handle any type at all, an instance of a generic class can only handle one specific type. Of course multiple instances can each handle a different type, but only one each. This is quite different to the Object class.

I don't know whether this has cleared up your confusion or not but, with so much information on the web about generics, I'm not prepared to spend any more time on it. Different programming languages work in different ways. There's nothing wrong with the way VB.NET works. If you don't like it then don't use it. If you want to use it, get over your preconceptions and get used to it. The fact that you want it to work a particular way doesn't mean that it should or that it will. I've been using VB.NET since 2003 and I have no issue with the Object class and how it works. It seems completely logical to me, and millions of others apparently.
 
Jmcilhinney Thank you very much for the clarification; and let me be clear I am not bantering against you personally in fact that is a very good explaination. The best one I have ever read regarding generics from the Microsoft Implementation.

And I was very aware of the work around through list of.

Thank you again because you have very clearly proven my point. Overly complicated a very simple concept. Object keyword would have worked just as well.


Instead specific type casting is required because of how they access data through the managed resources which I understand.
 
Back
Top