Of the classes that provide support for LINQ is the IEnumerable generic interface. In reality, a LINQ statement is an object of type IEnumerable. Based on this, instead of the Dim keyword, you can declare the statement using that interface. Inside the parentheses, enter the type of list that the collection variable contains. Here is an example: Imports System.Linq Imports System.Collections.Generic Public Class Employee Public EmployeeNumber As Integer Public FirstName As String Public LastName As String Public HourlySalary As Double Public Sub New(Optional ByVal Number As Integer = 0, Optional ByVal FName As String = "John", Optional ByVal LName As String = "Doe", Optional ByVal salary As Double = 0D) EmployeeNumber = Number FirstName = FName LastName = LName HourlySalary = salary End Sub End Class Module Exercise Public Function Main() As Integer Dim Employees() As Employee = { New Employee(971974, "Patricia", "Katts", 24.68), New Employee(208411, "Raymond", "Kouma", 20.15), New Employee(279374, "Hélène", "Mukoko", 15.55), New Employee(707912, "Bertrand", "Yamaguchi", 24.68), New Employee(294800, "Peter", "Mukoko", 18.85), New Employee(971394, "Gertrude", "Monay", 20.55) } Dim Empls As IEnumerable(Of Employee) = From StaffMembers In Employees Select StaffMembers Console.WriteLine("+========+============+===========+========+") Console.WriteLine("| Empl # | First Name | Last Name | Salary |") For Each Staff In empls Console.WriteLine("+--------+------------+-----------+--------+") Console.WriteLine("| {0,6} | {1,-10} | {2,-9} | {3,6} |", Staff.EmployeeNumber, Staff.FirstName, Staff.LastName, Staff.HourlySalary) Next Console.WriteLine("+=======+============+===========+=========+") Console.WriteLine() Return 0 End Function End Module This would produce:
Instead of processing a query locally, you can hand the job to an external method that would return the query. To create a method that returns a query, specify its return type as IEnumerable. If the method will receive the value it must process, you can pass it as argument. In the body of the method, create a (the) LINQ statement(s) as you see fit. Before the method closes, make sure it returns a value that either is of type IEnumerable or implements that interface. Here is an example: Imports System.Linq Imports System.Collections.Generic Module Exercise Function GetQuery(ByVal List As Double()) As IEnumerable(Of Double) Return From N In List Select N End Function Public Function Main() As Integer Dim Numbers() = {12.44, 525.38, 6.28, 2448.32, 632.04} Dim number = GetQuery(numbers) For Each Member In number Console.WriteLine(Member) Next Console.WriteLine() Return 0 End Function End Module This would produce:
In this example, we used a method that returned a list of simple values. In the same way, you can create a method that returns a list of objects. You can also create a method that returns a single value from a query.
Besides, or instead of, the Select statement in LINQ, the IEnumerable interface provides its own mechanism for selecting the values. This can be done using the Select() method that is overloaded with two versions whose syntaxes are: <ExtensionAttribute> _ Public Shared Function Select(Of TSource, TResult) ( _ source As IEnumerable(Of TSource), _ selector As Func(Of TSource, TResult) _ ) As IEnumerable(Of TResult) <ExtensionAttribute> _ Public Shared Function Select(Of TSource, TResult) ( _ source As IEnumerable(Of TSource), _ selector As Func(Of TSource, Integer, TResult) _ ) As IEnumerable(Of TResult) This method expects a variable that would hold the result of the selection. You can pass it a lambda expression. You don't have to specify the TSource and the TResult classes. After doing this, the IEnumerable variable can be used in a foreach loop. Here is an example: Imports System.Linq Imports System.Collections.Generic Public Class Employee Public EmployeeNumber As Integer Public FirstName As String Public LastName As String Public HourlySalary As Double Public Sub New(Optional ByVal Number As Integer = 0, Optional ByVal FName As String = "John", Optional ByVal LName As String = "Doe", Optional ByVal salary As Double = 0D) EmployeeNumber = Number FirstName = FName LastName = LName HourlySalary = salary End Sub End Class Module Exercise Public Function Main() As Integer Dim Employees() As Employee = { New Employee(971974, "Patricia", "Katts", 24.68), New Employee(208411, "Raymond", "Kouma", 20.15), New Employee(279374, "Hélène", "Mukoko", 15.55), New Employee(707912, "Bertrand", "Yamaguchi", 24.68), New Employee(294800, "Peter", "Mukoko", 18.85), New Employee(971394, "Gertrude", "Monay", 20.55) } Dim Empls As IEnumerable(Of Employee) = Employees.Select(Function(StaffMembers) StaffMembers) Console.WriteLine("+========+============+===========+========+") Console.WriteLine("| Empl # | First Name | Last Name | Salary |") For Each Staff In empls Console.WriteLine("+--------+------------+-----------+--------+") Console.WriteLine("| {0,6} | {1,-10} | {2,-9} | {3,6} |", Staff.EmployeeNumber,Staff.FirstName, Staff.LastName, Staff.HourlySalary) Next Console.WriteLine("+=======+============+===========+=========+") Console.WriteLine() Return 0 End Function End Module
To support conditions of a query, the Enumerable class is equipped with a method named Where that is overloaded with two versions. The syntax of one is: public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) Here is an example of calling it: Imports System.Linq Imports System.Collections.Generic Module Exercise Public Function Main() As Integer Dim Numbers() = { 637.58, 48.5, 12.44, 525.38, 45.3, 6.28, 2448.32, 632.04} Dim ListOfNumbers = From N In Numbers Select N For Each Number In ListOfNumbers Console.WriteLine(Number) Next Console.WriteLine("=+=+=+=+=+=+=+") Dim ListWhere = (From N In Numbers Select N).Where(Function(high) high > 500) For Each WhereCondition In ListWhere Console.WriteLine(WhereCondition) Next Console.WriteLine() Return 0 End Function End Module This would produce:
If you have a simple list of values of a primitive type and the LINQ variable is declared using the var keyword, we saw that you could sort it using the orderby operator. If the list is made of values that each is based on a class, you can also sort it the same way, in the IEnumerable expression. Here is an example: IEnumerable(Of Employee) empls = from staffMembers in employees orderby staffMembers.LastName select staffMembers; To support the ability to sort the values, the IEnumerable interface provides its own OrderBy() method that is overloaded with two versions. Their syntaxes are: Public Shared Function OrderBy(Of TSource, TKey) ( _ source As IEnumerable(Of TSource), _ keySelector As Func(Of TSource, TKey) _ ) As IOrderedEnumerable(Of TSource) Public Shared Function OrderBy(Of TSource, TKey) ( _ source As IEnumerable(Of TSource), _ keySelector As Func(Of TSource, TKey), _ comparer As IComparer(Of TKey) _ ) As IOrderedEnumerable(Of TSource) Here is an example: Imports System.Linq Imports System.Collections.Generic Public Class Employee Public EmployeeNumber As Integer Public FirstName As String Public LastName As String Public HourlySalary As Double Public Sub New(Optional ByVal Number As Integer = 0, Optional ByVal FName As String = "John", Optional ByVal LName As String = "Doe", Optional ByVal salary As Double = 0D) EmployeeNumber = Number FirstName = FName LastName = LName HourlySalary = salary End Sub End Class Module Exercise Public Function Main() As Integer Dim Employees() As Employee = { New Employee(971974, "Patricia", "Katts", 24.68), New Employee(208411, "Raymond", "Kouma", 20.15), New Employee(279374, "Hélène", "Mukoko", 15.55), New Employee(707912, "Bertrand", "Yamaguchi", 24.68), New Employee(294800, "Peter", "Mukoko", 18.85), New Employee(971394, "Gertrude", "Monay", 20.55) } Dim Empls As IEnumerable(Of Employee) = Employees.OrderBy(Function(staffMembers) staffMembers.LastName) Console.WriteLine("+========+============+===========+========+") Console.WriteLine("| Empl # | First Name | Last Name | Salary |") For Each Staff In empls Console.WriteLine("+--------+------------+-----------+--------+") Console.WriteLine("| {0,6} | {1,-10} | {2,-9} | {3,6} |", Staff.EmployeeNumber, Staff.FirstName, Staff.LastName, Staff.HourlySalary) Next Console.WriteLine("+=======+============+===========+=========+") Console.WriteLine() Return 0 End Function End Module Imagine you want to give the user the ability to sort the list but you want the list to be accessible from sections of the code. One way you can solve this problem is to declare a LINQ variable outside of the code sections but without initializing the variable, as long as you make sure the variable would be initialized before it is used. The problem with the Dim keyword is that you must initialize its variable when you declare it. The advantage with an IEnumerable variable is that you do not have to initialize it when declaring it. You can declare it, then specify its value in another section of the code. |
|
|||||||||||||||||||||||
|
We know how to create an array of (random) natural numbers and store it in a variable to use a query. Here is an example: Imports System.Linq Imports System.Collections.Generic Module Exercise Public Function Main() As Integer dim Numbers() = { 12, 44, 525, 38, 6, 28, 2448, 32, 632, 04 } Dim Number = From N In Numbers Select N For Each Member In number Console.WriteLine(Member) Next Console.WriteLine() Return 0 End Function End Module This would produce:
In some cases, you may want to work on a consecutive list of numbers such as 1, 2, 3, 4, 5, 6, 7, and 8. Instead of declaring a formal variable, the Enumerable class provides a method named Range that allows you to specify the first number of a range and a count of consecutive numbers to add to create a range. The syntax of the Enumerable.Range() method is: Public Shared Function Range ( _ start As Integer, _ count As Integer _ ) As IEnumerable(Of Integer) The first argument passed to this method is the beginning of the range. The second argument specifies how many numbers to add consecutively from the first. To use this method, you can declare a variable of type IEnumerable and assign a call to Enumerable.Range() that receives both arguments. Here is an example: Imports System.Linq
Imports System.Collections.Generic
Module Exercise
Public Function Main() As Integer
Dim Range As IEnumerable(Of Integer) = Enumerable.Range(22, 8)
Dim number = From N In Range Select N
For Each Member In number
Console.WriteLine(Member)
Next
Console.WriteLine()
Return 0
End Function
End Module
You can also declare the variable as type var. You would receive the same result:
If you want to restrict the result, you can add a where condition to it. Here is an example: Imports System.Linq
Imports System.Collections.Generic
Module Exercise
Public Function Main() As Integer
Dim Range = Enumerable.Range(96, 10)
Dim number = From N
In Range
Where N Mod 2 = 0
Select N
For Each Member In number
Console.WriteLine(Member)
Next
Console.WriteLine()
Return 0
End Function
End Module
This would produce:
When you create a LINQ statement, it produces a list. Although the list is of type IEnumerable, since this is only an interface, the result relies on an actual class to provide its characteristics. The class that gives you information about a result is called Enumerable. The Enumerable class in defined in the System.Linq namespace that is part of the System.Core.dll assembly. It is actually the Enumerable class that implements the methods declared in the IEnumerable interface. Because the Enumerable class is extremely big, we cannot review all of its methods. We will use them as we move on and when a particular method becomes necessary. As mentioned already, a LINQ statement produces an Enumerable list. You can then use that result to access a method of the class. For example, the IEnumerable.Count() method is used to know the number of items in the resulting list. You can access it from the resulting list. Here is an example: Imports System.Linq
Imports System.Collections.Generic
Public Class Employee
Public EmployeeNumber As Integer
Public FirstName As String
Public LastName As String
Public HourlySalary As Double
Public Sub New(Optional ByVal Number As Integer = 0,
Optional ByVal FName As String = "John",
Optional ByVal LName As String = "Doe",
Optional ByVal salary As Double = 0D)
EmployeeNumber = Number
FirstName = FName
LastName = LName
HourlySalary = salary
End Sub
End Class
Module Exercise
Public Function Main() As Integer
Dim Employees() As Employee =
{
New Employee(971974, "Patricia", "Katts", 24.68),
New Employee(208411, "Raymond", "Kouma", 20.15),
New Employee(279374, "Hélène", "Mukoko", 15.55),
New Employee(707912, "Bertrand", "Yamaguchi", 24.68),
New Employee(294800, "Peter", "Mukoko", 18.85),
New Employee(971394, "Gertrude", "Monay", 20.55)
}
Dim Empls As IEnumerable(Of Employee) = From StaffMembers
In Employees
Order By StaffMembers.LastName
Select StaffMembers
Console.WriteLine("+========+============+===========+========+")
Console.WriteLine("| Empl # | First Name | Last Name | Salary |")
For Each Staff In Empls
Console.WriteLine("+--------+------------+-----------+--------+")
Console.WriteLine("| {0,6} | {1,-10} | {2,-9} | {3,6} |",
Staff.EmployeeNumber, Staff.FirstName,
Staff.LastName, Staff.HourlySalary)
Next
Console.WriteLine("+=======+============+===========+=========+")
Console.WriteLine()
Console.WriteLine("Number of Employees: {0}", Empls.Count())
Console.WriteLine()
Return 0
End Function
End Module
This would produce: +========+============+===========+========+ | Empl # | First Name | Last Name | Salary | +--------+------------+-----------+--------+ | 971974 | Patricia | Katts | 24.68 | +--------+------------+-----------+--------+ | 208411 | Raymond | Kouma | 20.15 | +--------+------------+-----------+--------+ | 971394 | Gertrude | Monay | 20.55 | +--------+------------+-----------+--------+ | 279374 | Hélène | Mukoko | 15.55 | +--------+------------+-----------+--------+ | 294800 | Peter | Mukoko | 18.85 | +--------+------------+-----------+--------+ | 707912 | Bertrand | Yamaguchi | 24.68 | +=======+============+===========+=========+ Number of Employees: 6 Press any key to continue . . . Remember that you can still use the Dim keyword to declare the variable that would hold the resulting list. The same Dim keyword can be used for the result of a method call. Here are examples: Dim Empls As IEnumerable(Of Employee) = From StaffMembers In Employees Order By StaffMembers.LastName Select StaffMembers Dim total = Empls.Count() Since we have determined that a LINQ statement produces an Enumerable list, if you do not need the list itself, you can declare a variable that is the type returned by a method, put the statement in parentheses, and then access the method outside the closing parenthesis using the period operator. Here is an example: Dim Total = (From StaffMembers In Employees Order By StaffMembers.LastName Select StaffMembers).Count() Remember that the IEnumerable.Count() method returns the number of items in the result of the LINQ statement, not the number of items in the original list. The following examples illustrate it: Imports System.Linq
Imports System.Collections.Generic
Public Enum Genders
Female
Male
Unknown
End Enum
Public Class Employee
Public EmployeeNumber As Integer
Public FirstName As String
Public LastName As String
Public Gender As Genders
Public HourlySalary As Double
Public Sub New(Optional ByVal Number As Integer = 0,
Optional ByVal FName As String = "John",
Optional ByVal LName As String = "Doe",
Optional ByVal Gdr As Genders = Genders.Unknown,
Optional ByVal salary As Double = 0D)
EmployeeNumber = Number
FirstName = FName
LastName = LName
Gender = Gdr
HourlySalary = salary
End Sub
End Class
Module Exercise
Public Function Main() As Integer
Dim Employees() As Employee =
{
New Employee(971974, "Patricia", "Katts", Genders.Female, 24.68),
New Employee(408415, "Leslie", "Simms", Genders.Unknown, 15.72),
New Employee(208411, "Raymond", "Kouma", Genders.Male, 20.15),
New Employee(279374, "Hélène", "Mukoko", Genders.Female, 15.55),
New Employee(607575, "Hermine", "Kensley", Genders.Female, 12.55),
New Employee(707912, "Bertrand", "Yamaguchi", Genders.Male, 24.68),
New Employee(475022, "Leslie", "Simms", Genders.Unknown, 15.72),
New Employee(448660, "Helios", "Panko", Genders.Unknown, 12.69),
New Employee(294800, "Peter", "Mukoko", Genders.Male, 18.85),
New Employee(971394, "Gertrude", "Monay", Genders.Female, 20.55),
New Employee(680404, "Lydia", "Kensley", Genders.Female, 22.58)
}
Dim Empls As IEnumerable(Of Employee) =
From StaffMembers
In Employees
Order By StaffMembers.LastName
Select StaffMembers
Dim Men As Integer = (From Males
In Employees
Where Males.Gender = Genders.Male
Select Males).Count()
Dim Women As Integer = (From Females
In Employees
Where ((Females.Gender <> Genders.Male) And
(Females.Gender <> Genders.Unknown))
Select Females).Count()
Console.WriteLine("+========+============+===========+=========+========+")
Console.WriteLine("| Empl # | First Name | Last Name | Gender | Salary |")
Console.WriteLine("+========+============+===========+=========+========+")
For Each Staff In Empls
Console.WriteLine("| {0,6} | {1,-10} | {2,-9} | {3,-7} | {4,6} |",
Staff.EmployeeNumber, Staff.FirstName, Staff.LastName,
Staff.Gender, Staff.HourlySalary)
Console.WriteLine("+--------+------------+-----------+---------+--------+")
Next
Console.WriteLine()
Console.WriteLine("Number of Male Employees: {0}", Men)
Console.WriteLine("Number of Female Employees: {0}", Women)
Console.WriteLine()
Return 0
End Function
End Module
This would produce: +========+============+===========+=========+========+ | Empl # | First Name | Last Name | Gender | Salary | +========+============+===========+=========+========+ | 971974 | Patricia | Katts | Female | 24.68 | +--------+------------+-----------+---------+--------+ | 607575 | Hermine | Kensley | Female | 12.55 | +--------+------------+-----------+---------+--------+ | 680404 | Lydia | Kensley | Female | 22.58 | +--------+------------+-----------+---------+--------+ | 208411 | Raymond | Kouma | Male | 20.15 | +--------+------------+-----------+---------+--------+ | 971394 | Gertrude | Monay | Female | 20.55 | +--------+------------+-----------+---------+--------+ | 279374 | Hélène | Mukoko | Female | 15.55 | +--------+------------+-----------+---------+--------+ | 294800 | Peter | Mukoko | Male | 18.85 | +--------+------------+-----------+---------+--------+ | 448660 | Helios | Panko | Unknown | 12.69 | +--------+------------+-----------+---------+--------+ | 408415 | Leslie | Simms | Unknown | 15.72 | +--------+------------+-----------+---------+--------+ | 475022 | Leslie | Simms | Unknown | 15.72 | +--------+------------+-----------+---------+--------+ | 707912 | Bertrand | Yamaguchi | Male | 24.68 | +--------+------------+-----------+---------+--------+ Number of Male Employees: 3 Number of Female Employees: 5 Press any key to continue . . . These different techniques of calling and using the Count() method can be applied to most other methods of the Enumerable class.
If the values you are querying are numbers, you may want to find their average. To assist you, the Enumerable class provides a method named Average that is overloaded with a version for each numeric data type. The syntax for the double type is: public static double Average(this IEnumerable Here is an example of calling this method: Imports System.Linq Imports System.Collections.Generic Module Exercise Public Function Main() As Integer dim Numbers() = { 12.44, 525.38, 6.28, 2448.32, 632.04 } Dim Number = From N In Numbers Select N For Each Member In Number Console.WriteLine(Member) Next Console.WriteLine("---------------------") Console.WriteLine("Average: {0}", Number.Average()) Console.WriteLine() Return 0 End Function End Module This would produce:
If it is only the average that you want, you can include the LINQ statement in parentheses and call the Average method outside. Here is an example: Imports System.Linq
' Imports System.Collections.Generic
Module Exercise
Public Function Main() As Integer
dim Numbers() = { 12.44, 525.38, 6.28, 2448.32, 632.04 }
dim Average = (from N
In Numbers
Select N).Average()
Console.WriteLine("Average: {0}", Average)
Console.WriteLine()
Return 0
End Function
End Module
This would produce: Average: 724.892 Press any key to continue . . . Of course, you can add a Where condition if you want to restrict the result. |
|
|||||||||
|