Structures and ArrayList

  • Thread starter Thread starter Sueffel
  • Start date Start date
S

Sueffel

I'm having problems with this one:
I have a tructure that is being added to an arraylist, so I may have 15 of
these structure objects in an arraylist. now, what I want to do is this:

dim TT as MyStruct = New MyStruct

TT = MyArraylist.Item(3)

I have even tried this:

TT = CType(MyArrayList.Item(3), MyStruct)

Each case gives me a "Specified cast is invalid" exception.

Thanks
Ssueffel
 
Sueffel said:
I'm having problems with this one:
I have a tructure that is being added to an arraylist, so I may have
15 of these structure objects in an arraylist. now, what I want to
do is this:

dim TT as MyStruct = New MyStruct

TT = MyArraylist.Item(3)

I have even tried this:

TT = CType(MyArrayList.Item(3), MyStruct)

Each case gives me a "Specified cast is invalid" exception.


Can't reproduce the problem:

Structure mystruct
Public x As Integer
End Structure
'....
Dim tt As mystruct
Dim al As New ArrayList
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
tt = CType(al(3), mystruct) 'or Directcast instead of CType


--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html
 
Armin Zingler said:
Can't reproduce the problem:

Structure mystruct
Public x As Integer
End Structure
'....
Dim tt As mystruct
Dim al As New ArrayList
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
tt = CType(al(3), mystruct) 'or Directcast instead of CType


--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html

Okay, in my DLL, I have this:

Friend Class CommandList
Public Structure Simenz
Dim FunctionName As String
Dim NamespaceClass As String
Dim ParentMenu As String
Dim Discription As String
Dim MenuIndex As Integer
Dim Library As String
Sub New(ByVal Function_Name As String, _
ByVal Namespace_Class As String, _
ByVal Parent_Menu As String, _
ByVal Disc As String, _
ByVal Menu_Index As Integer, _
ByVal oLib As String)
FunctionName = Function_Name
NamespaceClass = Namespace_Class
ParentMenu = Parent_Menu
Discription = Disc
MenuIndex = Menu_Index
Library = oLib
End Sub
End Structure
Public ContainedFunction As ArrayList = New ArrayList()

Public Function List() As ArrayList
ContainedFunction.Add(New Simenz("TrackHeader",
"Forms.Tracking", "Processes", "Tracking Header Form", 0, "Mallorca.dll"))
ContainedFunction.Add(New Simenz("DEHeader", "Forms.DEHeader",
"Processes", "Data Entry Batch Header", 1, "Mallorca.dll"))
ContainedFunction.Add(New Simenz("Datez", "Math.Datez", Nothing,
"Date incriment command", 0, "Mallorca.dll"))
ContainedFunction.Add(New Simenz("LuhnMod", "Math.LuhnMod",
Nothing, "LuhnMod10 CheckDigit System", 0, "Mallorca.dll"))
ContainedFunction.Add(New Simenz("Numbahs", "Math.Numbahs",
Nothing, "Batch increment command", 0, "Mallorca.dll"))
Return ContainedFunction
End Function
End Class

And in my Application I have this:

Dim MyObj As Object
dim Libraries as String() = Directory.GetFiles(Application.StartupPath,
"*.dll")
dim Libb as String
For Each Libb in Libraries
MyObj = ClassByName(Libb,"CommandList")
If Not MyObj Is Nothing Then
Dim Cmdz as ArrayList = MyObj.List
Dim I as Integer
Dim Cmd as Simenz
For I = 0 To Cmdz.Count - 1
Cmd = DirectCast(Cmdz(I), Simenz) '***
Next
End If
Next

The 3 Astrisks is as far as I get, I get "Specified Cast is not valid."
exception. The DLL is a non-referenced Assembly that I'm doing Late-Binding
with using the following function:

Public Function ClassByName(ByVal strAssemblyFileName As String, ByVal
strClassName As String) As Object
Dim objAssembly As [Assembly] =
[Assembly].LoadFrom(strAssemblyFileName)
Dim objTemp As Object = objAssembly.CreateInstance( _
strClassName, _
False, _
BindingFlags.CreateInstance, _
Nothing, _
Nothing, _
Nothing, _
Nothing)
If objTemp Is Nothing Then
Throw New Exception("Plugin " & strAssemblyFileName & " could
not be loaded")
Else
Return objTemp
End If
End Function

I know, using Interfaces would be better, but couldn't get it to quite work
the way I need it to. When the Main App starts, it updates all these DLL's,
and the Interface kept binding immediatly and locking the file. But anyhew,
I'm not understanding this, the ArrayList is being passed just fine as far
as I can tell...

Thanks
Sueffel
 
Armin Zingler said:
Can't reproduce the problem:

Structure mystruct
Public x As Integer
End Structure
'....
Dim tt As mystruct
Dim al As New ArrayList
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
al.Add(New mystruct)
tt = CType(al(3), mystruct) 'or Directcast instead of CType


--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html

Forgot to mention that the structure is also defined in the Main App in a
module. Gonna try and put that in the form class and see what happens, I'm
also going to try and make the one in the DLL Shared.

Sueffel
 
<SNIP>

Structure mystruct
Public x As Integer
End Structure
'....
Dim tt As mystruct
Dim al As New ArrayList
al.Add(New mystruct)
al.Add(New mystruct)
tt = New MyStruct()
tt.x=5
al.add(tt)
al.Add(New mystruct)
al.Add(New mystruct)
tt = DirectCast(al(2), mystruct)

This code works just fine, not sure what is going on here :(

Sueffel
 
Sueffel said:
Forgot to mention that the structure is also defined in the Main App
in a module.

Then it is not the same structure. Maybe they have the same name, but they
are not equal. This is the reason for the exception.

I thought you did this because of the line
Dim Cmd as Simenz
and because you wrote you didn't reference the assemblies.
Gonna try and put that in the form class and see what
happens, I'm also going to try and make the one in the DLL Shared.



--
Armin

How to quote and why:
http://www.plig.net/nnq/nquote.html
http://www.netmeister.org/news/learn2quote.html
 
Sueffel said:
I'm not sure I follow you Armin, sorry.


Whenever you write text below the text you quote, a reader (like me) thinks
you are referring to the quoted text. I guess you are not referring to my
signature but to your problem.


What I am trying to say is: If you declare a structure within the
application _and_ within the DLL, it is not the _same_ structure even if the
names and members are equal. That's why you get an invalidCastException when
trying to assign an object to the variable. The type of the object is the
structure in the DLL, whereas the type of the variable is the structure in
the main application. The types are not equal, that's why you can't assign
the object.
 
Armin Zingler said:
Whenever you write text below the text you quote, a reader (like me) thinks
you are referring to the quoted text. I guess you are not referring to my
signature but to your problem.


What I am trying to say is: If you declare a structure within the
application _and_ within the DLL, it is not the _same_ structure even if the
names and members are equal. That's why you get an invalidCastException when
trying to assign an object to the variable. The type of the object is the
structure in the DLL, whereas the type of the variable is the structure in
the main application. The types are not equal, that's why you can't assign
the object.
So I'm screwed on that avenue. Okay, no biggie, time to rethink that
stratagy

Sueffel
 
Well, I don't know what the assemblyname will be. This is part of a
plugins system that uses LateBinding because of some drawbacks of
Interfaces. Basicaly, when a plugin is made, there's some strictness that
must be followed. My Application scanns all DLL's looking for a specific
Namespace and class, then executes the command that returns an ArrayList.
Well, the solution I found was to just itterate through this with a
For..Next loop and set the members that way. 3 lines of code extra, but it
works.
This way, incase you were wondering, I can use almost a combination of
CallByName and API. For example, consider the following function:

Public Function AddNums(ByVal Num1 as Integer, ByVal Num2 as Integer) As
Integer
Return Num1 + Num2
End Function

Now, in my plugin system, it would become this:

Namespace Math
Class AddNums
Public Function Command(ByVal Input As String) As String
{Code Here}
End Function
End Class
End Namespace

The Input is a ";" seperated list in my case. As the plugin designer, I
will expect 2 numbers, and when I call this function from my main assembly,
I will provide 2 numbers in a seperated list. This actualy isn't the
greatest example, but you may get the point.
Now, in My Main Program, I have the ClassByName function:

Public Function ClassByName(ByVal strAssemblyFileName As String, ByVal
strClassName As String) As Object
Dim objAssembly As [Assembly] =
[Assembly].LoadFrom(strAssemblyFileName)
Dim objTemp As Object = objAssembly.CreateInstance( _
strClassName, _
False, _
BindingFlags.CreateInstance, _
Nothing, _
Nothing, _
Nothing, _
Nothing)

Return objTemp
End Function

And from the afor mentioned array list, I can call and execute the function
in the plugin by passing variables, as such:

CommandList.Add(New Simenz("AddNumbers","Math.AddNums",Nothing,"Adds 2
numbers",0,"MyyDLL.dll")
Dim MyArr(1) As String={1,5}
Dim RetVal as String
Dim TT as New Simenz=CommandList.Items(0)
Dim MyObj as Object = ClassByName(TT.oLib,TT.NamespaceClass)
If Not MyObj is nothing then RetVal = MyObj.Command(MyArr)


So, it becomes flexible, with it's own limitations, but, as the main
application designer, I really don't need to know too much about the
back-end stuff. This system reallly wasn't designed for functions like
this, but more for forms that are 100% dynamic, but interact completly with
the parent app. now, I'm not a C++ programmer, so I had to figure out a
system that would allow me to do a plugin like they do, and without the use
of API's either. So, Latebinding was my answer, and I was having a problem
passing the critical info back and forth, but, putting laziness aside
solved it.

Thanks again Armin, you have actually taught me a very important lession
about OOP, even if it appears equal, it may not be equal at all.

Sueffel
 
Sueffel said:
Well, I don't know what the assemblyname will be. This is part
of a
plugins system that uses LateBinding because of some drawbacks of
Interfaces. [...]

I am still not satisfied with the situation. :-)

I still don't know
If you really would use Latebinding only, you can not declare the variable
"As Simenz".

The main question is: Do you know in which library the type "Simenz" is
declared?
- If yes, set a reference to the library in your main app, becaues you want
to use /just/ /that/ type.
- If no, how can you know that the type exists at all?


I guess, the situation is: You want the plugins to use a certain type
("Simenz" in this case), /and/ you want your main app to use the same type.
The only clean solution is to put the type into a 3rd DLL. Your main app and
the plugins will be able to use the type:


MainApp
/ |
/ |
/ |
(Plugins) |
\ |
\ |
\ |
3rd library (incl. Simenz)


(view with a fixed font size)


Both, the main app as well as the plugins will be using the /same/ type now.
This enables you to a) declare the variable As Simenz within the main app
and b) assign an object of that type returned by the plugin to the variable
declared in the main app.
 
I haven't ruled that out, and it's something I'm still thinking of. Right
now, the structure is declared in every DLL and in the main app. I'm not
happy and probably will make a "Common" DLL that will contain that type,
plus some other little goodies. One of these days I'm going to set this all
down in a paper and see what can be tweaked and fixed. One other thing I'm
thinking of doing, but need to test this one extensivly, is to keep the type
in the main app, and then reference that from the DLL. I'm keeping the same
Late-Bound system, but not sure how things would react to that. It would be
nice if it works the way I'm anticipating it, but I need to answer some
questions first.

Thanks again Armin,
Sueffel
 
Back
Top