LINQ Query returning Ienumerable - vb.net

I have the following 2 classes
Public Class LookupsModel
Implements IEnumerable(Of LookupModel)
Public _LookupModel() As LookupModel
Public Sub New(pArray As ArrayList)
_LookupModel = New LookupModel(pArray.Count - 1) {}
Dim i As Integer
For Each l As LookupModel In pArray
_LookupModel(i) = l
i += 1
Next
End Sub
Public Function GetEnumerator() As IEnumerator(Of LookupModel) Implements IEnumerable(Of LookupModel).GetEnumerator
Return New LookupEmum(_LookupModel)
End Function
Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
Return New LookupEmum(_LookupModel)
End Function
Public Property Heading1 As String
Public Property Heading2 As String
Public Property Heading3 As String
Public Property Heading4 As String
Public Property Heading5 As String
Public Property Heading6 As String
Public Property CalledBy As String
Public Property ParmName1 As String
Public Property ParmName2 As String
Public Property ParmName3 As String
Public Property ParmName4 As String
Public Property ParmName5 As String
Public Property ParmName6 As String
Public Property ValueFieldGetter() As Func(Of LookupModel, String)
Public Property DescriptionFieldGetter() As Func(Of LookupModel, String)
End Class
Public Class LookupModel
Public Sub New(ByVal Key As String, Optional ByVal Desc As String = Nothing, Optional Extra_1 As String = Nothing, Optional Extra_2 As String = Nothing, Optional Extra_3 As String = Nothing, Optional Extra_4 As String = Nothing)
Me.Field1 = Key
Me.Field2 = Desc
Me.Field3 = Extra_1
Me.Field4 = Extra_2
Me.Field5 = Extra_3
Me.Field6 = Extra_4
End Sub
Public Sub New()
Me.Field1 = Nothing
Me.Field2 = Nothing
Me.Field3 = Nothing
Me.Field4 = Nothing
Me.Field5 = Nothing
Me.Field6 = Nothing
End Sub
Public Property Field1 As String
Public Property Field2 As String
Public Property Field3 As String
Public Property Field4 As String
Public Property Field5 As String
Public Property Field6 As String
End Class
This is the linq query:
Dim lm As LookupsModel = GetLookupsModel(FieldID, lookup, LookupPage:=1, SearchField:=SearchField, SearchFields:=searchFields, SearchString:=String.Empty)
Dim lm2 As IEnumerable(Of LookupModel) = lm.Where(Function(p) p.Field1.Contains("A"))
I'm trying to query LookupsModel and only get the LookupModel collection where LookupModel.Field1 starts with "A". But the following query returns an Ienumerable of LookupModel, not the LookupsModel object with those items excluded. How do we accomplish this and get a LookupsModel object as a result?

You can't directly cast from an IEnumerable(Of LookpupModel) to a LookupsModel. You have a few options:
Add a constructor that takes an existing IEnumerable(Of LookupModel)
Convert the output of Where to an ArrayList and use your existing constructor.
But what's the point of LookupsModel in the first place? All you're doing is wrapping an array of LookupModel and not adding any additional functionality. Why not just stick with IEnumerable(Of LookupModel)?

Related

Return Distinct Objects with Linq

(I'm new in VB.Net) I have these three classes:
Public Class Classe_PIVA_Cond
Public Property my_codFiscale As String
Public Property my_presenzaDuplicati As Boolean
Public Property my_listaCondominii As New List(Of Classe_Condominio)
Public Sub New()
End Sub
Public Sub New(codFiscale As String, presenzaDuplicati As Boolean, listaCondominii As List(Of Classe_Condominio))
Me.my_codFiscale = codFiscale
Me.my_presenzaDuplicati = presenzaDuplicati
Me.my_listaCondominii = listaCondominii
End Sub
End Class
'==================================
Public Class Classe_Condominio
Public Property my_Studio As New Classe_Studio
Public Property my_Amministratore As New Classe_Amministratore
Public Property my_codCondominio As String
Public Property my_indirizzo As String
Public Property my_comune As String
Public Property my_cap As String
Public Property my_provincia As String
Public Property my_codFiscale As String
Public Sub New()
End Sub
Public Sub New(studio As Classe_Studio, amministratore As Classe_Amministratore, codCondominio As String, indirizzo As String, comune As String, cap As String, provincia As String, codFiscale As String)
Me.my_Studio = studio
Me.my_Amministratore = amministratore
Me.my_codCondominio = codCondominio
Me.my_indirizzo = indirizzo
Me.my_comune = comune
Me.my_cap = cap
Me.my_provincia = provincia
Me.my_codFiscale = codFiscale
End Sub
End Class
'==================================
Public Class Classe_Studio
Public Property my_codice As String
Public Property my_ragioneSociale As String
Public Property my_pIvaCodFisc As String
Public Sub New()
End Sub
Public Sub New(codice As String, ragioneSociale As String, pIvaCodFisc As String)
Me.my_codice = codice
Me.my_ragioneSociale = ragioneSociale
Me.my_pIvaCodFisc = pIvaCodFisc
End Sub
End Clas
I would try to return a List of distinct Classe_Studio.my_codice in a List(Of Classe_PIVA_Cond).
Any suggestion?
Try
Dim my_codiceDistinctList = Classe_PIVA_CondList
.SelectMany(Function(x) x.my_listaCondominii)
.Select(Function(y) y.my_Studio.my_codice)
.Distinct()
.ToList()

How to support contextual implicit conversions of custom object in Visual Basic .NET?

I want to use named error codes within my app. This should ensure, that every developer does not confuse numeric-only error codes with other codes, and also reduces the time a developer needs to realize what the error code should represent.
Compare this example:
Function New() As Integer
Return 0
End Function
with this example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
Of course, I could let the developers write like the following:
Function New() As Integer
Return 0 ' ERROR_SUCCESS
End Function
However, the code above raises a pitfall when a developer updates the actual return code but forgets about the comment. Some developer look at the actual return code and some at the comment. I want to mitigate that confusion.
I come up the following class (extract):
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Now I want to use this ErrorCodes class like in the following example:
Function New() As Integer
Return ErrorCodes.ERROR_SUCCESS
End Function
As expected, I will produce an exception (type conversion) since the actual value I return is a instance of the class ErrorCodes instead of the generic data type Integer.
As you can see with the ToString() function, I let the class automatically/implicitly converts the instanced object into the generic data type String, when the class instance is assigned to a String typed variable.
Is there a way to do the same with the generic data type Integer like I did with ToString()?
I am using the .NET Framework 4.0, as for compatibility reasons with Windows XP SP3.
Another way to say what I want:
Dim stringVariable As String = ErrorCodes.ERROR_SUCCESS ' should be "[0]ERROR_SUCCESS".
Dim integerVariable As Integer = ErrorCodes.ERROR_SUCCESS ' should be 0.
I do not want to trigger implicit conversion warnings/errors, or to force the developer to typecast explicitly.
Yes you can do that with the use of Conversion Operators.
Here is the code:
Public Class Form1
Public Class ErrorCodes
Private msName As String = Nothing
Private miValue As Integer = 0
Public Shared Widening Operator CType(ByVal ec As ErrorCodes) As String
Return ec.ToString
End Operator
Public Shared Narrowing Operator CType(ByVal ec As ErrorCodes) As Integer
Return ec.Value
End Operator
Public Shared ReadOnly ERROR_SUCCESS As ErrorCodes = New ErrorCodes("ERROR_SUCCESS", 0)
Public Shared ReadOnly ERROR_FAILED As ErrorCodes = New ErrorCodes("ERROR_FAILED", 1)
Private Sub New(ByVal psName As String, ByVal piValue As Integer)
msName = psName
miValue = piValue
End Sub
Public ReadOnly Property [Name] As String
Get
Return msName
End Get
End Property
Public ReadOnly Property [Value] As Integer
Get
Return miValue
End Get
End Property
Public Overrides Function ToString() As String
Return String.Format("[{0}]{1}", msName, miValue)
End Function
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim em As String = ErrorCodes.ERROR_SUCCESS
Dim ev As Integer = ErrorCodes.ERROR_SUCCESS
Dim mm As String = String.Format("String: {0}, Value: {1}", em, ev)
MsgBox(mm)
End Sub
End Class
More info here
Hope this helps.
This, as jmcilhinney pointed out, uses Enums and the Description attribute.
Here is the class
'requires
' Imports System.Reflection
' Imports System.ComponentModel
Public Class ErrorCodes
Public Enum ErrCode 'these are the error codes
'note that the codes should be unique
<Description("Success")> ERROR_SUCCESS = 0
<Description("Error A")> ERROR_A = 1
End Enum
Public Class InfoForErrCode
Public TheDescription As String
Public TheValue As Integer
Public AsString As String
End Class
Public Shared Function Info(TheError As ErrCode) As InfoForErrCode
Dim rv As New InfoForErrCode
rv.TheDescription = GetDescription(TheError)
rv.TheValue = TheError
rv.AsString = TheError.ToString
Return rv
End Function
Private Shared Function GetDescription(TheError As ErrCode) As String
Dim rv As String = ""
Dim fi As FieldInfo = TheError.GetType().GetField(TheError.ToString())
Dim attr() As DescriptionAttribute
attr = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute),
False), DescriptionAttribute())
If attr.Length > 0 Then
rv = attr(0).Description
Else
rv = TheError.ToString()
End If
Return rv
End Function
End Class
And here is how it can be used
Dim foo As ErrorCodes.ErrCode = ErrorCodes.ErrCode.ERROR_SUCCESS
Dim inf As ErrorCodes.InfoForErrCode = ErrorCodes.Info(foo)
Stop 'examine inf
foo = ErrorCodes.ErrCode.ERROR_A
inf = ErrorCodes.Info(foo)
Stop 'examine inf

Comparing list of class by string length and text comparison

I have a List(Of Abbreviation).
The class "Abbreviation" contains the string members "Input", "Output" and "CaseSensitive".
The class is stated below.
I would like to sort this list so that the class with the "Input"
"ZZZ"
comes before
"zz"
The comparison should thus first compare by string length, then by alphetical order, and then by CaseSensitive.
How could I sort the list this way?
Public Class Abbreviation
Implements IComparable
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Property Input() As String
Get
Return _sIn
End Get
Set(value As String)
_sIn = value
End Set
End Property
Public Property Output() As String
Get
Return _sOut
End Get
Set(value As String)
_sOut = value
End Set
End Property
Public Property CaseSensitive() As Boolean
Get
Return _bCaseSensitive
End Get
Set(value As Boolean)
_bCaseSensitive = value
End Set
End Property
Public Sub New(ByVal uInput As String, ByVal uOutput As String, ByVal uCaseSensitive As Boolean)
_sIn = uInput
_sOut = uOutput
_bCaseSensitive = uCaseSensitive
End Sub
End Class
First, you can simplify your code by using automatic properties. The compiler writes the get, set, and backer fields (the private fields). This is the preferred way in recent versions of Visual Studio if there is no extra code in the getter, setter.
Another small detail with your Sub New. It violates encapsulation to set the private fields directly. Always go through the Public Properties. There could be code in the setter that needs to run before storing the data in the private fields. Classes like to keep their data close to the vest in their private fields.
Example of Auto Implemented Properties
Public Property Input As String
Public Property Output As String
Public Property CaseSensitive As Boolean
The sort can be done in one line of code using a Linq query.
Dim orderedList = From abrev In lstAbreviations Order By abrev.Input.Lenght Descending Select abrev
To check the output...
For Each abrev As Player In orderedList
Debug.Print(abrev.Input)
Next
I think I got it, except the case sensitivity. CaseSensitive should come before CaseSensitive = False.
Public Class Abbreviation
Implements IComparable(Of Abbreviation)
Private _sIn As String = String.Empty
Private _sOut As String = String.Empty
Private _bCaseSensitive As Boolean = False
Public Function CompareTo(uOther As Abbreviation) As Integer _
Implements IComparable(Of Abbreviation).CompareTo
If uOther.Input.Length > Me.Input.Length Then
Return 1
ElseIf uOther.Input.Length < Me.Input.Length Then
Return -1
Else
If uOther.Input > Me.Input Then
Return 1
Else
Return -1
End If
End If
End Function

Filter List of Class by Property Value and List Of Value

I have a Devexpress Gridcontrol bound to a custom class.
The class looks like this:
Public Class AuditList
Public CasualtyList As List(Of CasualtyRecords)
Public MedsList As List(Of CasualtyRecords.Medications)
Public Property FilterString As CriteriaOperator
Public Sub New()
CasualtyList = New List(Of CasualtyRecords)
MedsList = New List(Of CasualtyRecords.Medications)
End Sub
Public Class CasualtyRecords
Private _primary As New PS
Public Property PrimarySurvey As PS
Get
Return _primary
End Get
Set(value As PS)
_primary = value
End Set
End Property
Public Sub New()
Vitals = New List(Of VitalRecords)
End Sub
Public Property Vitals As List(Of VitalRecords)
Public Property Meds As List(Of Medications)
ReadOnly Property MedCount As Integer
Get
Return Meds.Count
End Get
End Property
Property Id As Integer
Property ClinicalImpression As String
Property Disposal As String
Property Age As Integer
Property Gender As String
Class PS
Public Property Airway As Integer
Public Property Breathing As Integer
Public Property Circulation As Integer
Public Property Rate As Integer
End Class
Class Medications
Public Property MedName As String
End Class
End Class
End Class
This is an example of a filter type I am trying to create:
"[Gender] ='Male' AND [Medications].[MedName] = 'Paracetamol' AND [Age] >100"
Is this possible with the class constructed as shown, or perhaps do I need to implement some other interface?
I imagine that it would look something like this with LINQ
Dim b As New CasualtyRecords
b = a.CasualtyList.Where(Function(x) x.Meds.Any(Medications.Med = "Paracetamol") And x.Gender = "Male" And x.Age > 20)
Thanks
I was able to achieve the required results using this LINQ query
Dim newrecords = a.CasualtyList.Where(
Function(x) x.Meds.Any(
Function(b) b.MedName = "Paracetamol") _
And x.Gender = "Male" And x.Age > 20).ToList()

Assigning values to an object and its nested object

I am a novice and am missing something simple. I have two Classes
Public Class Param
Public Property temperature As String
Public Property display As Boolean
Public Property storage As Boolean
Public Property reason As Boolean
Public Property stats As Object
Public Property errors As Object
End Class
Public Class getTemperature
Public Property method As String
Public Property params As Param()
Public Property id As String
End Class
I want to declare and assign values to the objects but I keep getting the error "Object reference not set to an instance of an object" when trying to assign values to items within param. I don't understand, I have created both the object GetTemperature and the object Params, what am I missing?
Dim GetTemp As New getTemperature
GetTemp.method = TextBoxMethod.Text
GetTemp.id = TextBoxID.Text
Dim params As New Param
params.temperature = "true"
'GetTemp.params(0) = params
I have also tried, but get the same response:
Dim GetTemp As New getTemperature
GetTemp.method = TextBoxMethod.Text
GetTemp.id = TextBoxID.Text
GetTemp.params(0).temperature = "True"
Try this:
Public Class Param
Public Property temperature As String
Public Property display As Boolean
Public Property storage As Boolean
Public Property reason As Boolean
Public Property stats As Object
Public Property errors As Object
End Class
Public Class getTemperature
Public Property method As String
Public Property params As List(Of Param)
Public Property id As String
Public Sub New()
params = New List(Of Param)
End Sub
End Class
So you could write something like:
Dim a As New getTemperature
a.params.Add(New Param)
It will work if you remove the parenthesis
Public Class getTemperature
Public Property method As String
Public Property params As Param
Public Property id As String
End Class
and then
Dim GetTemp As New getTemperature
GetTemp.method = TextBoxMethod.Text
GetTemp.id = TextBoxID.Text
Dim params As New Param
params.temperature = "true"
GetTemp.params = params