VB6 how to consume a VB.NET array of Objects? - vb.net

I have a VB.NET Dll, registered as COM interoperability, that exposes something like this:
Class Society
with a:
Property ListPersons As Person()
This is the VB.NET Code:
Public Class Society
...
<System.Xml.Serialization.XmlArrayItemAttribute("Person", Form:=System.Xml.Schema.XmlSchemaForm.Unqualified)> _
Public Property ListPersons() As Person()
Get
Return Me.ListPersonsField
End Get
Set
Me.ListPersonsField = value
Me.RaisePropertyChanged("ListPersons")
End Set
End Property
I have to fill that list with VB6 but I cannot find the way

I have struggled with this issue a lot in the past and to be honest I could not find a solution to pass an array of object.
One of the solutions I used in the past was to pass the data of the single object as parameters and then create the object in the .net DLL and add it to your list.
Example
<ServiceContract()>
Public Interface IPersonAdd
<OperationContract()>
Function AddPerson(ByVal id As Integer, ByVal value As Integer) As Boolean
End Interface
Public Function AddPerson(ByVal id As Integer, ByVal value As Integer)
Dim p as new Person(id, value)
ListPersons.Add(p)
End Function

Related

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.

vb.net/Linq: how can I use a Linq using Generic classes?

I have the next structure:
public class mysample
public property status as integer
end class
Dim mylist=new List(Of mysample)
Dim item as new mysample
item.status=1
mylist.add(item)
Dim item1 as new mysample
item2.status=1
mylist.add(item1)
...
I have next function which it is calculating something:
Function test(Of T)(newstatus as integer, mylist as List(of T)) as integer
Dim res as integer = myList.Where(Function(x) x.status=newstatus).First.status
Return res
End function
The call is where I am interested to execute: test(Of mysample)(2, mylist)
I have mysample in different projects and they can not be in the same for this reason I decided to use generic list to do my Linq calcultion.
THE PROBLEM IS IN FUNCTION WHICH TELL ME STATUS IS NOT MEMBER OF T OBJECT.
How can I solve this issue? all clases has status but I have different classes and I pass the name as generic type.
Do the classes share a common base class or interface? If so you should place a filter on the generic type like this:
Function test(Of T as CommonBaseClassOrInterface)(newstatus as integer, mylist as List(of T)) as integer
That will allow you to access any members on CommonBaseClassOrInterface. If they currently don't share a base class or interface you should consider adding one, making sure that Status is a member.
If you can't give them a base class or interface for some reason, you can still do this using reflection, but I DO NOT recommend going that direction.
STATUS IS NOT MEMBER OF T OBJECT.
Yes, because you have not constraint T in any way. It would be perfectly legal to call
test(Of Integer)(2, new list(of Integer))
which would fail because Integer does not have a status property. You either need to constrain T to be of some type that has a status property (either a base class or a common interface), or don't make it generic:
Function test(newstatus as integer, mylist as List(of mystatus)) as integer
Dim res as integer = myList.Where(Function(x) x.status=newstatus).First.status
Return res
End function
I have mysample in different projects
You mean you have several classes names mystatus in several projects? Then they are not the same class.
all classes has status but I have different classes and I pass the name as generic type
The create at least an interface that has a Status property and use that to constrain the generic parameter in Test.

Vb, sorting lists

I have a question concerning sorting lists of classes in VB.Net.
It seems every subject which is discussing this kind of sorting is not really clear for me.
I have a class Language with the following variables:
- Lang as a string
- Knowledge as a integer
I have got a list containing a couple of language classes in it. How can I sort on the Lang variable (Alphabetically sort the language classes in the list)?
Greetings,
Implement IComparable on your class, then use Sort:
Private Class Language : Implements IComparable(Of Language)
Public Property Lang As String
Public Property Knowledge As Integer
Sub New(lang As String)
Me.Lang = lang
End Sub
Public Function CompareTo(other As Language) As Integer _
Implements IComparable(Of Language).CompareTo
Dim comp As Integer = Me.Lang.CompareTo(other.Lang)
'If comp = 0 Then Return Me.Knowledge.CompareTo(other.Knowledge)
Return comp
End Function
End Class
Sub Main()
Dim lst As New List(Of Language)
lst.Add(New Language("fr"))
lst.Add(New Language("en"))
lst.Add(New Language("de"))
lst.Sort()
End Sub
EDIT: Added a hint on how to sort by multiple properties.
This was answered in a previous StackOverflow question: Sort a List of Object in VB.NET
Use Sort along with a custom function to compare the Lang variable.
theList.Sort(Function(x, y) x.Lang.CompareTo(y.Lang))

Problem returning object from VB.NET COM Assembly into VBA (Access)

I have an assembly in VB .NET 2.0 that I am trying to use to call a webservice.
This will be COM visible, and return the results to Access in VBA.
The .NET Assembly passes all tests and executes perfectly.
I was experiencing "Object does not support this property or method" errors when calling the methods from VBA.
I broke it down to a certain object that was being returned and added some test methods to the .NET DLL.
There is a "Patient" object I want to return.
It looks like this (made it very very simple to test it):
Option Strict On
Option Explicit On
<ComClass(Patient.ClassId, Patient.InterfaceId, Patient.EventsId)> _
Public Class Patient
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "672dfbd9-8f3a-4ba2-a33d-89fef868f2b9"
Public Const InterfaceId As String = "74a9c54c-4427-4d31-8220-3258ecda345d"
Public Const EventsId As String = "dc25515e-1bb7-4a66-97d5-270c00d792a9"
#End Region
Public Sub New()
MyBase.New()
End Sub
Public Property StorePatientID() As Integer
Get
Return m_StorePatientID
End Get
Set(ByVal value As Integer)
m_StorePatientID = value
End Set
End Property
Private m_StorePatientID As Integer
End Class
So about as simple as an object can be really.
I have a method that just returns a dummy record, just to test it:
Public Function GetPatientTest() As Patient
Dim patient As New Patient
patient.StorePatientID = 99
Return patient
End Function
This fails with the afformentioned error.
HOWEVER,
This method succeeds!
Public Function GetPatientArrayTest() As Patient()
Dim strings As New List(Of Patient)
Dim patient As New Patient
patient.StorePatientID = 99
strings.Add(patient)
Return strings.ToArray
End Function
The DLL is made com visible through "Properties" page.
Builds to project/bin/debug, always do a rebuild.
Always seems to be updated with new methods etc when I look at it in VBA so don't think it's looking at an old version.
Obviously no funny dependencies with these methods.
Really really struggling with this.
EDIT:
Update 16/03/2011 - Added VBA script
Public Function FindPatientsTest(ByVal surname As String, ByVal surnameBeginsWith As Boolean, ByVal forename As String, ByVal forenameBeginsWith As Boolean, ByVal dateOfBirth As String)
Dim token As String
token = Login()
Dim patient As SCIStoreWS60.patient
Set patient = New SCIStoreWS60.patient
'// This doesn't work.
'// When adding a "Watch" to the function, I can see it returns an "Object/Patient" and is the correct results
'// When adding a "Watch" to the variable "patient" I can see it is a "Patient/Patient"
patient = sciStore.GetPatientTest()
'// This works fine
Dim something As Variant
something = sciStore.GetPatientArrayTest()
End Function
Update 16/03/2011 5 minutes later - Chastising myself
Sorry, I just worked it out.
I need to "Set" the patient variable.
Set patient = sciStore.GetPatientTest()
Why didn't I need to do this for the "something" variant?
So, yes, you need to Set object references, but not arrays.

LINQ Except using custom Comparer

I am trying to use the "Except" method on a LINQ result set using a custom implementation if IEqualityComparer to exclude certain results based on the value of a single field from the result set.
So, in simplified form I have...
'' Get collection of published sites...
Dim List1 = (From i In db.Sites _
Where (i.StatusID = published) _
Select i.SiteID, _
i.SiteName)
'' Find those with a pending site, but exclue all those whose SiteID is in List1...
Dim insComparer = New insCompare
Dim List2 = (From i In db.Sites _
Where (i.StatusID = pending) _
Select i.SiteID, _
i.SiteName).Except(List1, insComparer)
My Comparer is as follows...
Public Class insCompare
Implements System.Collections.Generic.IEqualityComparer(Of Object)
Public Function Equals1(ByVal x As Object, ByVal y As Object) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Object).Equals
Return IIf(x.SiteID = y.SiteID, True, False)
End Function
Public Function GetHashCode1(ByVal x As Object) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Object).GetHashCode
Return x.SiteID.ToString.ToLower.GetHashCode()
End Function
End Class
I get an invalid cast exception on the ".Except" line with the message "Unable to cast object of type '...insCompare' to type 'System.Collections.Generic.IEqualityComparer'"
Can anyone cast light on why this might be please.
Your problem here is that you implement IEqualityComparer(Of Object), but your lists are List(Of AT) where AT is an anonymous type, so you can't implement IEqualityComparer(Of AT).
I think your choices are:
Declare a class/struct to hold the SideID/SiteName, and select into an instance of that class, then implement IEqualityComparer(Of NewClass).
Use late-bound calls (ie. option explicit off, like it appears you are doing now), and put a .Cast(Of Object)() call on both lists before calling Except.
Use the following code.
from t in db.Sites
where
!
(from t0 in db.Sites2
select new {
t0.SomeID
}).Contains(new { t.SomeID })
select t
this is based in not in condition. I think this will help you. U are doing some complex thing.
It looks like it's asking that your comparer implement the non-generic interface IEqualityComparer, whereas yours implements IEqualityComparer (Of Object), which is a different interface.
It looks like you are using a database as the back end. You can't provide a custom comparer for this, as it can't be mapped to TSQL.
Have you tried Contains? i.e. where !List1.Contains(i.SiteID)?