Tuesday, April 7, 2015

VB.net extension method - shared method (C# static) : Multiple Field Sorting by Field Names Using Linq

I am trying to use the code  in VB.NET to do multiple column sort of  a list.

After conversion to VB.NET, trying to put in a class, then it says has to put in Module,


Then put in Module it says cannot be "Shared"

Note: All functions in the module are shared
Error 1 Methods in a Module cannot be declared 'Shared'.
So no way to add to VB.Net.(wrong, above code can be in VB.NET)

I just compiled it to a C# DLL and referenced in VB.Net

But still a trick, you have to make a shared (see yellow highlight) of Class StudentRepository, then sort worked in VB.NET

Not easy at all.

------------------------------------------------------------------------------------------

Sub Main() Dim sortExpressions As List(Of Tuple(Of String, String)) = New List(Of Tuple(Of String, String)) Dim fieldName As String = "Score" Dim sortOrder As String = "desc" sortExpressions.Add(New Tuple(Of String, String)(fieldName, sortOrder)) Dim studentList As List(Of Student) = StudentRepository.GetStudentList() studentList = studentList.MultipleSort(sortExpressions).ToList()

------------------------------------------------------------------------------------------
Public NotInheritable Class StudentRepository
    Private Sub New()
    End Sub
    Private Shared Students As List(Of Student) = Nothing

    Public Shared Function GetStudentList() As List(Of Student)
        ' Make sure the same student list is returned
        If Students IsNot Nothing Then
            Return Students
        End If

        ' If no previously created list, make a new one and fill in data
        Students = New List(Of Student)()
        Dim now = DateTime.Now

        Dim rand = New Random()
        For i As Integer = 1 To 100
            Dim student = New Student()
            student.Id = i
            student.Name = "Student Name No." + (i Mod 10).ToString()
            student.Enrollment = now.AddDays(i Mod 3)
            student.Score = 60 + CInt(rand.NextDouble() * 40)

            Students.Add(student)
        Next

        Return Students
    End Function
End Class

-------------------------------------------------------------------------------

Module Utility
    ''' <summary>
    ''' 1. The sortExpressions is a list of Tuples, the first item of the tuples is the field name,
    '''    the second item of the tuples is the sorting order (asc/desc) case sensitive.
    ''' 2. If the field name (case sensitive) provided for sorting does not exist in the object,
    '''    exception is thrown
    ''' 3. If a property name shows up more than once in the "sortExpressions",
    '''    only the first takes effect.
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <param name="data"></param>
    ''' <param name="sortExpressions"></param>
    ''' <returns></returns>
    <System.Runtime.CompilerServices.Extension()> _
    Public Shared Function MultipleSort(Of T)(data As IEnumerable(Of T), sortExpressions As List(Of Tuple(Of String, String))) As IEnumerable(Of T)
        ' No sorting needed
        If (sortExpressions Is Nothing) OrElse (sortExpressions.Count <= 0) Then
            Return data
        End If

        ' Let us sort it
        Dim query As IEnumerable(Of T) = From item In data Select item
        Dim orderedQuery As IOrderedEnumerable(Of T) = Nothing

        For i As Integer = 0 To sortExpressions.Count - 1
            ' We need to keep the loop index, not sure why it is altered by the Linq.
            Dim index = i
            ' Dim expression As Func(Of T, Object) = Function(item) item.[GetType]().GetProperty(sortExpressions(index).Item1).GetValue(item, Nothing)
            Dim expression As Func(Of T, Object) = Function(item) item.[GetType]().GetProperties.First(Function(pr) pr.Name = "name").GetValue(item, Nothing)
            If sortExpressions(index).Item2 = "asc" Then
                orderedQuery = If((index = 0), query.OrderBy(expression), orderedQuery.ThenBy(expression))
            Else
                orderedQuery = If((index = 0), query.OrderByDescending(expression), orderedQuery.ThenByDescending(expression))
            End If
        Next

        query = orderedQuery

        Return query
    End Function
End Module

No comments:

Post a Comment