2013-09-29 4 views
1

Эта функция использует алгоритм пузыря для сортировки списка IO.DirectoryInfo по их Name.Передайте свойство IO.DirectoryInfo как параметр функции?

Как я могу указать в параметре свойство, которое я буду сортировать по списку?

Например: "Drive", "Имя", "name.length", "Directory.Parent", и т.д ...

То, что я думал, что это хорошая идея (может быть, это не хорошо, я не не знаю, насколько это можно улучшить) заключается в том, чтобы передать параметр как строку, а затем передать строку как ...? Здесь я потерялся.

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:

Уведомление эта часть кода выше:

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

Что мне нужно, чтобы вызвать функцию определения свойство, которое я хочу вместо этого свойство «Name».

ОБНОВЛЕНИЯ 2

Попытка использовать решение @Sriram Sakthivel, но он вызывает исключение на [собственности] переменный о несовместимом литье между УнарноеВыражением к 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 
+0

Вы ищете [это] (http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet)? –

+0

@Sriram Sakthivel спасибо за комментарий, это не то, что я ищу (или, я думаю, с большим количеством кода C#, я не могу понять все, что делает этот код), см. Мое обновление. – ElektroStudios

+0

Извинения за то, что вы не даете пример VB.NET, но вот способ C# получить имя свойства через лямбда, который похож на то, что вы ищете: http://stackoverflow.com/questions/671968/retrieving- property-name-from-lambda-expression Надеюсь, это даст вам руку с вашим вопросом. –

ответ

0

Если я понял, что вы хотите правильно, код Sriram Sakthivel устанавливает часть того, что требуется, но не может доставить то, что вы хотите.

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

Вы должны установить строку-аргумент типа с именем целевого свойства («Name», «CreationTime» и т.д.), и получить это свойство одного из элементов списка (первый , например) через GetProperty; помните, что запрос LINQ относится к элементам, а не ко всему списку.

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 

ПРИМЕЧАНИЕ. Я просто предлагаю исправление кода, чтобы вы могли получить то, что хотите, насколько я понял. Я не рекомендую полагаться на Reflection по умолчанию (.GetValue довольно медленный).

+0

Ваш код замечательный, он работает со свойствами строк, но не с свойствами promp, такими как «Root», «Parent» и т. Д., Также я также не нашел способ работать подуровнями как «Parent.Name». Было бы слишком сложно улучшить код? Я попытался передать аргументы как «Parent.ToString» или внутри функции changeging «curProp.tostring», но все, что я получаю, - это исключения. – ElektroStudios

+0

@ElektroHacker вы можете использовать GetProperties(), и вы получите массив со всеми свойствами данного типа; но свойства, а не методы или поля. Если вы хотите получить все, вам, возможно, придется полагаться на getMembers(). В свойствах нет «уровней», это просто простые переменные. Для чего вы хотите эту функцию, я думаю, что ее свойств достаточно. Но если вы хотите продолжать его развивать, вы можете назвать его рекурсивно для всех членов данного типа (для каждого элемента в списке); хотя я думаю, что это не часть этого вопроса :) – varocarbas

+0

Наконец, я получил функцию, которая работает для всех свойств «onelevel», изменяющих в вашем решении все типы «String» для «Object» и добавляя «.ToString.Length») .Max() ", я знаю, что использование типов объектов не рекомендуется, но нет другого легкого решения для моего новичка. В любом случае мне нужно передать аргумент «Parent.Name.Length», я попытаюсь узнать, как я могу использовать GetMembers, что вы сказали мне, чтобы делать то, что мне нужно. Благодарю. – ElektroStudios

1

Upto одном уровне свойств вы можете сделать с MemberExpression. obj.Prop.Prop2 требует использования 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 

Может быть ошибка синтаксиса. Я в основном программист на C#. Я просто использовал инструмент конвертер для Vb.net

Edit:

Поскольку у вас есть список каталогов, у вас есть сомнения, как передать dir.Name параметр не имеет значения, на самом деле, dir.Name просто передается захватить PropertyInfo из Это.

Итак, вы можете просто пройти New DirectoryInfo("somedirectory").Name. Попробуйте следующее

Dim dir = New DirectoryInfo("SomeArbitaryStringIsEnough") 

For Each folderinfo In BubbleSort_List(Folders, Function() dir.Name) 
    MsgBox(folderinfo.Name) 
Next 
+0

Спасибо, я никогда не думал, что это будет необходимо использовать методы отражения, тогда это так сложно, как кажется, код, работающий только для свойств одного уровня, тоже должен быть большим, но я до сих пор не знаю, как решить мою проблему , вы показали мне, как использовать параметр непосредственно с объектом directoryinfo, чтобы вы поместили «Function() dir.Name» в качестве параметра, но у меня есть список объектов directoryinfo, а не уникальный объект directoryinfo, поэтому я не знаю, как заменить что переменная «dir» в «dir.Name», которую вы использовали. Пожалуйста, посмотрите мое обновление и еще раз спасибо! – ElektroStudios

+0

Параметр не имеет значения, 'dir.Name' просто передается для его захвата' PropertyInfo'. Поэтому вы можете просто передать 'New DirectoryInfo (« somedirectory »). Имя« достаточно ». Поскольку я просто объявлял переменную dir с 'New DirectoryInfo (" somedirectory ")' и передал 'dir.Name', он будет работать. –

+1

отредактировал мой ответ для уточнения –