2013-09-29 8 views
1

이 함수는 버블 알고리즘을 사용하여 속성으로 IO.DirectoryInfo의 목록을 정렬합니다.IO.DirectoryInfo 속성을 매개 변수로 함수에 전달 하시겠습니까?

매개 변수에 목록을 정렬 할 속성을 어떻게 지정할 수 있습니까? 예를 들어

: "드라이브", "이름", "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 

내가 필요하면 내가 대신 "이름"속성을 원하는 속성을 지정하는 함수를 호출하는 것입니다.

UPDATE 2

@Sriram Sakthivel 용액을 사용하려고하지만 MemberExpression UnaryExpression 사이에 호환 주조 대한 [등록] 변수에 예외를 던진다.

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

[this] (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 

당신은 target 속성 ("이름", "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 속성에는 적합하지 않습니다. 또한 하위 수준을 "Parent.Name"으로 처리하지도 못했습니다. 코드를 개선하기가 너무 어려울까요? "Parent.ToString"또는 "curProp.tostring"을 변경하는 함수 내부에서 인수를 전달하려고 시도했지만 예외는 모두 발생합니다. – ElektroStudios

+0

@ElektroHacker 당신은 GetProperties()를 사용할 수 있습니다. 그러면 주어진 타입의 모든 속성을 가진 배열을 얻을 수 있습니다; 속성이나 메소드 나 필드가 아닙니다. 모든 것을 얻으려면 getMembers()에 의존해야합니다. 속성에는 "레벨"이 단순한 변수가 아닙니다. 이 기능을 원한다면 속성으로 충분하다고 생각합니다. 그러나 계속 진화시키고 싶다면 주어진 유형의 모든 구성원 (목록의 각 항목)에 대해 재귀 적으로 호출 할 수 있습니다. 비록이 질문의 일부가 아닌 것 같아요 :) – varocarbas

+0

마침내 나는 "모든"문자열 유형을 "Object"로 변경하고 ".ToString.Length"를 추가하여 모든 "onelevel"속성에서 작동하는 함수를 얻었습니다. .Max() ", 객체 유형을 사용하는 것이 가장 권장되지는 않지만 이것에 대한 내 초보자 경험을위한 다른 쉬운 해결책이 아님을 알고 있습니다. 어쨌든 인수로 "Parent.Name.Length"를 전달해야하므로 필자가 원하는 것을 수행하도록 GetMembers를 사용할 수있는 방법을 배우려고합니다. 감사. – ElektroStudios

1

최대 레벨은 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

에 대한 그냥 사용 변환기 도구

편집 : 당신은 디렉토리 목록을 가지고 있기 때문에

당신은 문제가 실제로 dir.Name 단지의 PropertyInfo을 캡처 전달하지 않습니다 dir.Name 매개 변수를 전달하는 방법 의심의 여지가 그것.

New DirectoryInfo("somedirectory").Name을 전달하면됩니다. 다음을 시도하십시오.

+0

고마워, 나는 그것이 반사 기술의 사용법이 필요하다고 상상하지 못했다. 그리고 나서 그것은 너무 열심히 일 것이다. onelevel 속성에 대해서만 작동하는 코드는 훌륭해야하지만, 여전히 내 문제를 해결하는 방법을 모른다. , 당신은 내가 매개 변수로 매개 변수를 직접 사용하는 방법을 보여 주었다. "Function() dir.Name"을 매개 변수로 넣었으나, 나는 directoryinfo 객체가 아닌 directoryinfo 객체의 목록을 가지고있어서 대체 방법을 모른다. 그 "dir"변수는 "dir.Name"에서 사용했습니다. 내 업데이트를보고 다시 한 번 감사드립니다! – ElektroStudios

+0

매개 변수는 실제로 중요하지 않습니다.'dir.Name'은 방금'PropertyInfo'를 캡처하기 위해 전달됩니다. 따라서 새로운 DirectoryInfo ("somedirectory")를 단순히 전달하면됩니다. Name'으로 충분합니다. 방금'New DirectoryInfo ("somedirectory")'로 변수 dir을 선언하고'dir.Name'을 전달 했으므로 작동 할 것입니다. –

+1

명확한 대답 내 편집 –