Passing unknown variabels

Posted on 2011-09-14
Last Modified: 2012-05-12
How do you in VB.NET pass variabels to a subrutine if you dont know the variabel types or the number of variabels beeing passed to the sub before runtime?

In the sub there must also be a way to determin what info has been passed to the sub.

The sub will of cause have logic to process the values after it has been detected what type of data has been passed, but that is not part of this problem/solution.

is there a way to code this?
Question by:daghoff
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions

Expert Comment

ID: 36537056
If they're not complex variable types, can you just put them in an array, and pass that?

LVL 40
ID: 36537161
For the Unknonw number of variables, you use a ParamArray.

For the unknow type, you define it as an array of Objects. My Visual Studio is being patched right now. I cannot check if I have it exactly right, but you get the concept.
Sub Foo(ByVal X As Byte, ByVal ParamArray A() As Object)

   Dim W As Object
   For Each W In A
      Select Case True
         Case TypeOf W Is Integer
             CInt(W) = 10
         Case TypeOf W Is TextBox
         Case Else
             Throw New NotSupportedException ("Type not supported")
      End Select

End Sub

Open in new window

LVL 17

Expert Comment

ID: 36537167
put these in a Dictionary(Of String, Object) from the calling procedure (which I assume knows the variabe types) and name them appropriately, e.g
1.Calling routine would:
Dim ObjDICT As New Dictionary(Of String, Object)
ObjDICT.Add("Label", New Label With {.Name = "MyLabel", .Text = "MyLabelText"})
ObjDICT.Add("TextBox", New TextBox With {.Name = "MyTextBox", .Text = "MyTextBoxText"})

Open in new window

2. The recieving routine will then use the keys of the dictionary to cast the object to its type
Function RecVFUNCT(ByVal xDict As Dictionary(Of String, Object) As Boolean
  For Each x In xDict.Keys
     Select Case x
        Case "Label"
           Dim Lbl = DirectCast(xDict.Item(x), Label)
        Case "TextBox"
           Dim Tbx = DirectCast(xDict.Item(x), TextBox)
     End Select
End Function

Open in new window

SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.


Author Comment

ID: 36537198
Forgot to mention that the variabels to be passed are always two or more arrays of the same length.  The arrays may be defined as string, integer, boolean etc. but that is not known before the program is run.

You mean this can be solved by putting it all in a new array?
LVL 40
ID: 36537455
An array is an object. The array of Object variables used as a ParamArray can receive them. You will end up with an array of Array. The looping will just be a little more involved if you need to access individual values, something like:

Extra comment: ParamArray can be used alone. But if you have other parameters to pass, ParamArray should be the last one.

Sub Foo(ByVal x As Byte, ByVal ParamArray a() As Object)

  For Each w() As Object In A
    For i As Integer = 0 To 10 - 1
      Select Case True
        Case TypeOf w(0) Is Integer
        Case TypeOf w(0) Is TextBox
          DirectCast(w(i), TextBox).Text = "Foo"
        Case Else
          Throw New NotSupportedException("Type not supported")
      End Select

End Sub

Open in new window

You should be able to call it with code similar to the following:
Dim a() As Integer
Dim b() As TextBox

'Fill the arrays

foo(10, a)
foo(10, b)
foo(10, a, b)
foo(10, b, a)

Open in new window


Author Comment

ID: 36548686
Thanx for the answers. I liked the ParamArray approche best because it reduces the calling code to just one line as it should be.

But I forgot to mention that the arrays passed to the sub is to be returned. What my sub does is to sort them so the big question is how do I get them back? ParamArray does not allow ByRef.

I have an application where I need to sort arrays acording to one of them. How many and what type varies from place to place in the code. So insted of having the sort logic eveywhere I was hoping it could be put into a sub.

Perhaps there is no simple solution? Does anyone have a good aproche that realy solves my problem in a simpler way than just putting the sort logic eveywhere?

Or is there a specialiced multi array sort function/command already in place in VB.NET that I can use?
LVL 40
ID: 36550342
An array is a class and is already a reference. These types of objects are always passes as a reference, no matter if you use ByVal or ByRef. Changing ParamArray is the same as changing the passed array.

This is a common misconception. ByVal and ByRef works only for value types, objects made from a structure or form the basic types.

Author Comment

ID: 36558918
I knew that arrays are always passed in a "ByRef" way, but acording to what I have learned about ParamArray that is not the case. But it actually works as my slitly modified code below shows. The value that is modified in the sub is accessable after the sub has finished.

Public Class Form1
    Dim IA(3) As Integer
    Dim SA(3) As String
    Dim BA(3) As Boolean

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        IA(1) = 3 : IA(2) = 2 : IA(3) = 1
        SA(1) = "B" : SA(2) = "A" : SA(3) = "C"
        BA(1) = True : BA(2) = False : BA(3) = True
        MsgBox("Initial value before calling sub: " & SA(2))
        Foo1(3, SA, IA, BA)
        MsgBox("Updated value after calling sub: " & SA(2))
    End Sub

    Private Sub Foo1(ByVal NumValues As Byte, ByVal ParamArray A() As Object)
        Dim Vc As Integer
        For Each W() As Object In A    '<<---- Error in this line!! *****************************************
            For Vc = 1 To NumValues
                Select Case True
                    Case TypeOf W(Vc) Is Integer
                        MsgBox("We have an Integer array")
                    Case TypeOf W(Vc) Is String
                        MsgBox("We have a String array")
                        W(Vc) = "4444444444444"
                    Case TypeOf W(Vc) Is Boolean
                        MsgBox("We have a Boolean array")
                End Select
    End Sub
End Class

But there are still one more problem. In the line marked above I get these type of errors shown below when the passed array is not defined as String. How do I overcome that problem?
Unable to cast object of type 'System.Int32[]' to type 'System.Object[]'.
Unable to cast object of type 'System.Boolean[]' to type 'System.Object[]'.

LVL 40

Accepted Solution

Jacques Bourgeois (James Burger) earned 500 total points
ID: 36560891
First of all, .NET arrays always start at an indice of 0 in .Net. An array declared IA(3) has 4 elements, from IA(0) to IA(3). The indice you give in the declaration is not the number of elements, it is the indice of the upper bound. You ar losing resources by not using element 0.

Second, you do not need to pass the number of values as a parameter, you can get it from the array itself by calling array.GetLength(0). More often, you will however array.GetUpperBound(0) that gives you the indice of the highest element. The 0 is there to specify that you want the first dimension, because an array could be a multi-dimensioned array.

Third, I do not understand the cause of the error, one of those strange ones, probably due to the way For Each is implemented. But you can use a standard loop with a counter instead.

Fourth. Even then, the way you were doing the stuff, it would not have worked W(1), W(2) and W(3) are all of type Array. TypeOf would have not worked the way you implemented it. You need to look into the array to get the type of one of its elements. A being passed as an Object, simply cast each of its elements to an array (b in my code) and then look into the array.

Finally, this is one of those situations were Option Strict should be Off. If you work with Option Strict On, as you should, the following code won't work. Simply copy it in a module and set Option Strict Off in that module.
Option Strict Off
Public Module ModuleStrictOff
Private Sub Foo1(ByVal NumValues As Byte, ByVal ParamArray A() As Object)

  Dim Vc As Integer
  Dim b As Array

  For Vc = 0 To A.GetUpperBound(0)
    b = DirectCast(A(Vc), Array)
    Select Case True
      Case TypeOf b(1) Is Integer
        MsgBox("We have an Integer array")
      Case TypeOf b(1) Is String
        MsgBox("We have a String array")
        b(2) = "4444444444444"
      Case TypeOf b(1) Is Boolean
        MsgBox("We have a Boolean array")
    End Select

End Sub

Open in new window


Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article explains how to create and use a custom WaterMark textbox class.  The custom WaterMark textbox class allows you to set the WaterMark Background Color and WaterMark text at design time.   IMAGE OF WATERMARKS STEPS Create VB …
Article by: jpaulino
XML Literals are a great way to handle XML files and the community doesn’t use it as much as it should.  An XML Literal is like a String ( Literal, only instead of starting and ending with w…
Finding and deleting duplicate (picture) files can be a time consuming task. My wife and I, our three kids and their families all share one dilemma: Managing our pictures. Between desktops, laptops, phones, tablets, and cameras; over the last decade…
This video shows how to use Hyena, from SystemTools Software, to update 100 user accounts from an external text file. View in 1080p for best video quality.

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question