Pregunta

This function uses the bubble algorithm to sort a list of IO.DirectoryInfo by their Name property.

How I can specify in a parameter the property that I will to sort the list?

For example: "Drive", "Name", "Name.Length", "Directory.Parent", etc...

What I thought like a good idea (maybe is not good, I don't know how much can be improved this) is to pass the parameter as string and then cast the string as...? Here is where I'm lost.

Public Shared Function BubbleSort_List(list As List(Of IO.DirectoryInfo), ByVal SortByProperty As ...) As List(Of IO.DirectoryInfo)
    Return list.Select(Function(s) New With { _
        Key .OrgStr = s, _
        Key .SortStr = System.Text.RegularExpressions.Regex.Replace( _
                       s.Name, "(\d+)|(\D+)", _
                       Function(m) m.Value.PadLeft(list.Select(Function(folder) folder.Name.Length).Max, _
                       If(Char.IsDigit(m.Value(0)), " "c, Char.MaxValue))) _
    }).OrderBy(Function(x) x.SortStr).Select(Function(x) x.OrgStr).ToList

End Function

UPDATE:

Notice this part of the code above:

list.Select(Function(folder) folder.Name.Length).Max

What I need is to call the function specifying the property that I want instead "Name" property.

UPDATE 2

Trying to use the @Sriram Sakthivel solution but it throws an exception at the [property] variable about incompatible casting between UnaryExpression to MemberExpression.

    Imports System.Reflection
    Imports System.Linq.Expressions


Private Sub Test(sender As Object, e As EventArgs) Handles MyBase.Shown

    ' Here I create the list
    Dim Folders As List(Of IO.DirectoryInfo) = _
        IO.Directory.GetDirectories("E:\Música\Canciones", "*", IO.SearchOption.TopDirectoryOnly) _
        .Select(Function(p) New IO.DirectoryInfo(p)).ToList()

    ' Here I try to loop the list at the same time I try to sort it, 
    ' specifying the property I want using @Sriram Sakthivel solution,
    ' This part does not work because the second parametter is wrong.
    For Each folderinfo In BubbleSort_List(Folders, Function() Name)
        MsgBox(folderinfo.Name)
    Next

End Sub


    Private Function BubbleSort_List(list As List(Of IO.DirectoryInfo), exp As Expression(Of Func(Of Object))) As List(Of IO.DirectoryInfo)

        Dim [property] As PropertyInfo = DirectCast(DirectCast(exp.Body, MemberExpression).Member, PropertyInfo)

        Return list.Select(Function(s) New With { _
            Key .OrgStr = s, _
            Key .SortStr = System.Text.RegularExpressions.Regex.Replace( _
                           s.Name, "(\d+)|(\D+)", _
                           Function(m) m.Value.PadLeft(list.Select(Function(folder) DirectCast([property].GetValue(folder, Nothing), String).Length).Max(), _
                           If(Char.IsDigit(m.Value(0)), " "c, Char.MaxValue))) _
        }).OrderBy(Function(x) x.SortStr).Select(Function(x) x.OrgStr).ToList

    End Function
¿Fue útil?

Solución 2

If I understood what you want correctly, the Sriram Sakthivel code sets part of what is required but cannot deliver what you want.

For Each folderinfo In BubbleSort_List(Folders, "Name")
    MsgBox(folderinfo.Name)
Next

You have to set a string-type argument with the name of the target property ("Name", "CreationTime", etc.), and retrieve this property from one of the list items (the first one, for example) via GetProperty; bear in mind that the LINQ query refers to the items, not to the whole list.

Private Function BubbleSort_List(list As List(Of IO.DirectoryInfo), propName As String) As List(Of IO.DirectoryInfo)

    Dim curProperty As PropertyInfo = list(0).GetType().GetProperty(propName)

    Return list.Select(Function(s) New With { _
        Key .OrgStr = s, _
        Key .SortStr = System.Text.RegularExpressions.Regex.Replace( _
                       s.Name, "(\d+)|(\D+)", _
                       Function(m) m.Value.PadLeft(list.Select(Function(folder) DirectCast(curProperty.GetValue(folder, Nothing), String).Length).Max(), _
                       If(Char.IsDigit(m.Value(0)), " "c, Char.MaxValue))) _
    }).OrderBy(Function(x) x.SortStr).Select(Function(x) x.OrgStr).ToList

End Function

NOTE: I am just proposing a correction of your code to allow you to get what you want as I understood it. I am not recommending to rely on Reflection by default (.GetValue is pretty slow).

Otros consejos

Upto single level of properties you can do with MemberExpression. obj.Prop.Prop2 requires use of UnaryExpression

Private Shared Sub DoSomething(list As List(Of DirectoryInfo), exp As Expression(Of Func(Of Object)))
    Dim member As MemberExpression

    If (TypeOf exp.Body Is UnaryExpression) Then
        member = DirectCast(DirectCast(exp.Body, UnaryExpression).Operand, MemberExpression)
    Else
        member = DirectCast(exp.Body, MemberExpression)
    End If

    Dim [property] As PropertyInfo = DirectCast(member.Member, PropertyInfo)

'You could then use it like
list.Select(Function(folder) DirectCast([property].GetValue(folder, Nothing), String).Length).Max()
End Sub

Private Shared Sub Main()
Dim dir = New DirectoryInfo("somedirectory")
DoSomething(list, Function() dir.Parent)
    DoSomething(list, Function() dir.Name)
    DoSomething(list, Function() dir.FullName)

    DoSomething(list, Function() dir.Parent.Name)'Requires additional effort
End Sub

May be syntax error. am basically c# programmer. I just used converter tool for Vb.net

Edit:

Since you have list of directories you have a doubt how to pass dir.Name parameter doesn't matter actually, dir.Name is just passed to capture PropertyInfo of it.

So you can simply pass New DirectoryInfo("somedirectory").Name. Try the following

Dim dir = New DirectoryInfo("SomeArbitaryStringIsEnough")

For Each folderinfo In BubbleSort_List(Folders, Function() dir.Name)
    MsgBox(folderinfo.Name)
Next
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top