问题
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
回答1:
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).
回答2:
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
来源:https://stackoverflow.com/questions/19081003/pass-an-io-directoryinfo-property-as-a-parameter-to-a-function