Visual Basic 2008 9.0 .NET Examples and Ebook
  Home

New in Visual Basic 2008 - 9.0

Vorig Onderwerp

Object Oriented Programming

Query Methods

Vorig Onderwerp

Lambda Expressions

|

LINQ - Language Integrated Query

Volgend Onderwerp
Define a Query Method

Define a Query Method

Where

Where

OfType

OfType

Deferred Query Evaluation

Deferred Query Evaluation

ToList and ToArray

ToList and ToArray

Singleton Queries

Singleton Queries

Projection with Select

Projection with Select



Define a Query Method


When we want to filter elements from all our IEnumerable(Of T) collections based on some predicate, we could add an ( extension ) method with a predicate argument to select the elements.

Next example defines a extension method GetWhere in module MyEnumerable :


Option Strict On
Option Infer On
Public Class Counter
    Private m_Value As Integer
    Public Property Value() As Integer
        Get
            Value = m_Value
        End Get
        Set(ByVal value As Integer)
            m_Value = value
        End Set
    End Property
End Class
Public Module MyEnumerable
    <System.Runtime.CompilerServices.Extension()> _
    Public Function GetWhere(Of T)(ByVal source As IEnumerable(Of T), _
                                   ByVal predicate As Func(Of T, Boolean)) _
                                                            As IEnumerable(Of T)
        Dim getWhereList As New List(Of T)
        For Each item As T In source
            If predicate.Invoke(item) Then
                getWhereList.Add(item)
            End If
        Next
        GetWhere = getWhereList
    End Function
End Module
Public Class Example1
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        Dim predicate As Func(Of Counter, Boolean) = _
                                            Function(counter) counter.Value > 15
        Dim query1 = MyEnumerable.GetWhere(source, predicate)              ' (1)
        For Each counter As Counter In query1
            Console.WriteLine(counter.Value)
        Next
        Console.WriteLine()
        '
        Dim query2 = source.GetWhere(Function(counter) counter.Value < 25) ' (2)
        For Each counter As Counter In query2
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 20
 30

 10
 20

This extension method can now be called directly (1) or on any instance of type IEnumerable(Of T) (2).

For more details about these extensions, read the topic about extension methods.


Klik hier om terug naar boven te gaan.  Up


Where


Actually it was not necessary to define this extension.
Class System.Linq.Enumerable already defines an extension method Where(Of TSource)(ByVal source As IEnumerable(Of TSource), ByVal predicate As Func(Of TSource, Boolean)) As IEnumerable(Of TSource) which is in scope when namespace System.Linq is imported.


Public Class Example2
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        Dim predicate As Func(Of Counter, Boolean) = _
                                            Function(counter) counter.Value > 15
        Dim query1 = System.Linq.Enumerable.Where(source, predicate)
        For Each counter As Counter In query1
            Console.WriteLine(counter.Value)
        Next
        Console.WriteLine()
        '
        Dim query2 = source.Where(Function(counter) counter.Value < 25)
        For Each counter As Counter In query2
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 20
 30

 10
 20

It is possible to reject the behaviour of the extension Where of Enumerable. This can be done by not importing the Linq namespace.

One could also do this by defining an own extension method ( like the first example did ) with the same name ( Where ). This closer extension would then have higher priority than the imported extension, at least when it is define "closer" then Linq. For instance in the same assembly as the clients using this user-defined extension method.
If we change the name of extension method GetWhere to Where, the above example would execute our implementation, instead of the imported one, when a call to Where is made.

A method like Where of class Enumerable is often called a "query
method", because it can be used to filter/query data.


Klik hier om terug naar boven te gaan.  Up


OfType


Another extremely usefull query extension method from class Enumerable is OfType(Of TResult)(ByVal source As IEnumerable) As IEnumerable(Of TResult).

This extension of IEnumerable allows us to filter all IEnumerable collections into a strongly typed IEnumerable(Of T) collection.


Public Class Example3
    Public Shared Sub Main()
        Dim source1 = New Object() {1, "two", "3"c, "four", 5.0}
        Dim words As IEnumerable(Of String) = source1.OfType(Of String)()
        For Each word As String In words
            Console.WriteLine(word)
        Next
        Console.WriteLine()
        '
        Dim source2 As New ArrayList
        source2.Add(New Counter With {.Value = 10})
        source2.Add(New Counter With {.Value = 20})
        source2.Add(New Counter With {.Value = 30})
        Dim counters As IEnumerable(Of Counter) = source2.OfType(Of Counter)()
        For Each counter As Counter In counters
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 two
 four

 10
 20
 30

All String elements for the IEnumerable collection source1 ( with elements of type Object ) are placed in a strongly type IEnumerable(Of String) collection.

Because methods like Where and OfType work on an instance IEnumerable(Of T), but also deliver an IEnumerable(Of T) object, they can be combined to more complex "query expressions" :


Public Class Example4
    Public Shared Sub Main()
        Dim source = New Object() {1, "two", "3"c, "four", 5.0}
        Dim predicate1 As Func(Of String, Boolean) = _
                                               Function(text) text.Contains("o")
        Dim predicate2 As Func(Of String, Boolean) = _
                                             Function(text) text.StartsWith("f")
        Dim words As IEnumerable(Of String)
        words = source.OfType(Of String).Where(predicate1).Where(predicate2)
        For Each word As String In words
            Console.WriteLine(word)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 four

Klik hier om terug naar boven te gaan.  Up


Deferred Query Evaluation


Next example illustrates how queries are only evaluated the moment they are used, this is called "deferred query evaluation".

If, between two iterations, a query is manipulated, the manipulation will reflect on that second iteration (2).


Public Class Example5
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        Dim query = source.Where(Function(counter) True)
        '
        For Each counter As Counter In query                               ' (1)
            Console.WriteLine(counter.Value)
        Next
        Console.WriteLine()
        '
        source(1) = New Counter With {.Value = 200}
        '
        For Each counter As Counter In query                               ' (2)
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 10
 20
 30

 10
 200
 30

Our own GetWhere from MyEnumerable did not have this behaviour :


Public Class Example6
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        Dim query = source.GetWhere(Function(counter) True)
        '
        For Each counter As Counter In query                               ' (1)
            Console.WriteLine(counter.Value)
        Next
        Console.WriteLine()
        '
        source(1) = New Counter With {.Value = 200}
        '
        For Each counter As Counter In query                               ' (2)
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

The query was not deferred and immediately evaluated when the GetWhere method was called.

If a deferred query behaviour is desired, we can achieve this in our query method by delivering an iterator/enumerator, instead of immediately returning our filtered data. This iterator will only filter the internally referenced datasource the moment the iterator is used ( for instance in a For Each ) :


Klik hier om terug naar boven te gaan.  Up


ToList and ToArray


Class System.Linq.Enumerable defines some extensions of IEnumerable(Of T) that can be used to immediately execute a query, this in contrast to the default deferred behaviour. These extension are ToArray() As T() and ToList() As List(Of T).


Public Class Example8
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        Dim query = source.Where(Function(counter) True)
        '
        Dim queryArray As Counter() = query.ToArray()
        Dim queryList As List(Of Counter) = query.ToList()
        '
        source(1) = New Counter With {.Value = 200}
        '
        For Each counter As Counter In queryArray                          ' (1)
            Console.WriteLine(counter.Value)
        Next
        Console.WriteLine()
        '
        For Each counter As Counter In queryList                           ' (2)
            Console.WriteLine(counter.Value)
        Next
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 10
 20
 30

 10
 20
 30

The queries assigned to queryArray and queryList are immediately evaluated.


Klik hier om terug naar boven te gaan.  Up


Singleton Queries


Query extension of IEnumerable(Of T) that deliver a single value are also immediately evaluates.

A few of those singleton query methods are illustrated below :


Public Class Example9
    Public Shared Sub Main()
        Dim source = New Counter() {New Counter With {.Value = 10}, _
                                    New Counter With {.Value = 20}, _
                                    New Counter With {.Value = 30}}
        '
        Console.WriteLine(source.Any())
        Console.WriteLine(source.All(Function(counter) counter.Value Mod 2 = 0))
        Console.WriteLine(source.Average(Function(counter) counter.Value))
        Console.WriteLine(source.ElementAt(2).Value)
        Console.WriteLine(source.First().Value)
        '
        Console.ReadLine()
    End Sub
End Class
Download Broncode

Output :

 True
 True
 20
 30
 10

Any returns True is elements are present.

All returns True if the predicate is correct for all elements.

Average returns the average of all Decimals of all element. Average expects a selector that specifies how the element can be converted to a Decimal.


Klik hier om terug naar boven te gaan.  Up


Projection with Select


Extension method 'Select(Of TSource, TResult)(ByVal source As IEnumerable(Of TSource), ByVal selector As Func(Of TSource, TResult)) As IEnumerable(Of TResult)' can be used to project the result of a query ( of 'TSource elements ) into a instance of type 'TResult'.

selector defines the expression used to project the resultvalues. This is often in an anonymous type.


Objects of anonymouse type are used to gather the projected information.


Updated On : 2008-10-01

Download Broncode

Published On : 2008-11-06

Query Methods

Vorig Onderwerp

Lambda Expressions

|

LINQ - Language Integrated Query

Volgend Onderwerp

New in Visual Basic 2008 - 9.0

Vorig Onderwerp

Object Oriented Programming

  Home  
Nederlands
Nederlands

Add to favorites (IE).


No printable version available.