1

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
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • Are you looking for [this](http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet)? – Sriram Sakthivel Sep 29 '13 at 17:35
  • @Sriram Sakthivel thanks for comment, is not what I'm looking for (or I think so, with a lot of extensive C# code I can't understand all of what that code does), please see my update. – ElektroStudios Sep 29 '13 at 17:42
  • Apologies for not giving a VB.NET example, but here is a C# way of getting a property name via a lambda, which is similar to what you are looking for : http://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression Hopefully this will give you a hand with your question. – Jason Evans Sep 29 '13 at 18:19

2 Answers2

1

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
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Thanks, I've never imagined that would be necessary the usage of reflection techniques, then it's so hard than it seems, the code working only for onelevel properties should be great too, but I still don't know how to solve my problem, you shown me how to use the parametter directly with a directoryinfo object so you put "Function() dir.Name" as parametter, but I have a list of directoryinfo objects not a unique directoryinfo object so I don't know how to replace that "dir" variable at "dir.Name" that you've used. Please see my update and thanks again! – ElektroStudios Sep 29 '13 at 18:54
  • Parameter doesn't matter actually, `dir.Name` is just passed to capture `PropertyInfo` of it. So you can simply pass `New DirectoryInfo("somedirectory").Name` is enough. As I did just declare a variable dir with `New DirectoryInfo("somedirectory")` and pass `dir.Name` It will work. – Sriram Sakthivel Sep 29 '13 at 19:12
  • Maybe that will solve the property problem, I've followed your instructions but the Cast problem stills (UnaryExpression/MemberExpression), I've supposed the cast problem was 'cause the parametter I were passing were wrong but like the cast problem perssist the reason could be syntax error translation?. I've never used reflection things I'm not able to solve that little cast problem by myself sorry – ElektroStudios Sep 29 '13 at 19:42
  • Well, I feel bad asking for more and also both solutions works great i don't know which to mark, thanks for all. I will create another question about the same problem if you could help me about retrieving variable properties. – ElektroStudios Sep 29 '13 at 20:20
0

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).

varocarbas
  • 12,354
  • 4
  • 26
  • 37
  • Your code is great it works with strings properties but not with promp properties as "Root", "Parent", etc, also neither I did not found the way to work sublevels as "Parent.Name". It would be too hard to improve the code?, I've tried to pass an arguments as "Parent.ToString" or inside the function changging "curProp.tostring" but all I get are exceptions. – ElektroStudios Sep 29 '13 at 19:49
  • @ElektroHacker you can use GetProperties() and you will get an array with all the properties of the given type; but properties, not methods or fields. If you want to get everything, you might have to rely on getMembers(). Properties do not have "levels" are just simple variables. For what you want this function I think that it is enough with properties. But if you want to keep evolving it you might call it recursively for all the members in the given type (for each item in the list); although I guess that this is not part of this question :) – varocarbas Sep 29 '13 at 19:52
  • Finally I've get it the function working for all "onelevel" properties changing in your solution all "String" types to "Object" and adding ".ToString.Length).Max()", I know using object types is not the most recommended but no other easy solution for my newbie experience about this. Anyways I need to pass the "Parent.Name.Length" as argument, I will try to learn about how I can use GetMembers that you've told me for do what I need. thanks. – ElektroStudios Sep 29 '13 at 20:05
  • Well, I feel bad asking for more and also both solutions works great i don't know which to mark, thanks for all. I will create another question about the same problem if you could help me about retrieving variable properties. – ElektroStudios Sep 29 '13 at 20:21
  • 1
    @ElektroHacker you don't need to feel bad: you know the rules; just apply them. You have to define the problem properly and make the question as generally-applicable as possible. Here you asked about properties and this is what this answer (together with the Sriram Sakthivel bits) is about. If, after this answer you realise that you really need a different thing, you should take it as a help to understand the problem properly and thus solve it by your own (or ask a new question). – varocarbas Sep 30 '13 at 07:28