.net 如何使用LINQ或Lambda基于子属性订购集合?

.net 如何使用LINQ或Lambda基于子属性订购集合?,.net,vb.net,linq,lambda,.net,Vb.net,Linq,Lambda,我得到以下提供的字符串表达式: “ChildObject.FullName”…其中ChildObject是MyObject1类型的实例属性 ChildObject有一个名为“FullName”的属性,我想根据这个子属性“FullName”值对类型为“MyObject1”的集合进行排序 我可以整天直接在MyObject1上的属性上执行此操作,但在子实例上执行此操作时,我遇到了两个难题,无法让所有的部分都正常工作。主要的两个挑战是: MyObject1有几个不同的子属性类型,因此我无法硬编码Chil

我得到以下提供的字符串表达式:

“ChildObject.FullName”…其中ChildObject是MyObject1类型的实例属性

ChildObject有一个名为“FullName”的属性,我想根据这个子属性“FullName”值对类型为“MyObject1”的集合进行排序

我可以整天直接在MyObject1上的属性上执行此操作,但在子实例上执行此操作时,我遇到了两个难题,无法让所有的部分都正常工作。主要的两个挑战是:

  • MyObject1有几个不同的子属性类型,因此我无法硬编码ChildObject的类型。字符串可以是任何类型
  • 排序表达式是字符串,而不是已知类型
  • 对于上面的#2,我可以使用反射来获取子属性的类型,但我无法让它全部工作。我有以下内容,它编译并运行,但排序没有任何不同:

    'SortExpression below is a String like: "ChildObject.FullName"
    MyObject1List = MyObject1List.OrderBy(Function(x)
          Dim t As Type = x.GetType()
          Dim tp As Type = t.GetProperty(SortExpression.Split(".").ElementAt(0)).PropertyType()
          Return tp.GetProperty(Request.CompareExpression.Split(".").ElementAt(1))
          End Function).ToList()
    
    在表达式的最后一行返回的值之上(如果我在OrderBy方法之外运行代码,则会提供我所需的“全名”信息。因此代码必须接近,但仍然不起作用

    关于如何实现这一点,有什么想法吗?我试图阻止的是对子类型上的一系列“If”块进行硬编码,然后将其类型硬编码为sort或OrderBy方法


    谢谢!

    如果我正确理解了这个问题(免责声明-这是我编写的第一个vb.net代码,从语法上讲可能不是最好的-我是用c#first编写的),实现这一点的一种方法是执行以下操作

    假设您的MyObject 1如下所示:

    Public Class MyObject1
    
        Private mChildObject As SortableChildObject
    
        Public Property ChildObject() As SortableChildObject
            Get
                ChildObject = mChildObject
            End Get
            Set(value As SortableChildObject)
                mChildObject = value
            End Set
        End Property
    End Class
    
    ' Implement IComparable using reflection - just look up the property to
    ' sort on based on the "SortExpression" property 
    Public MustInherit Class SortableChildObject
        Implements IComparable
    
        Protected MustOverride ReadOnly Property SortExpression() As String
    
        Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
    
            ' Make sure the object we are comparing to is also our type
            Dim oo As SortableChildObject = TryCast(obj, SortableChildObject)
            If oo Is Nothing Then
                Throw New ArgumentException("I cannot compare these two objects")
            End If
    
            ' Get the value to sort on for this object
            Dim thisVal As IComparable = GetSortableValue(Me, SortExpression)
            If thisVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for this")
            End If
    
            ' Get the value to sort on for the object we are comparing to
            Dim thatVal As IComparable = GetSortableValue(oo, oo.SortExpression)
            If thatVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for that")
            End If
    
            ' Use the IComparable implementation of the properties we are comparing
            Return thisVal.CompareTo(thatVal)
        End Function
    
        Private Function GetSortableValue(obj As Object, sortExpression As String) As IComparable
    
            Dim prop As PropertyInfo = obj.GetType().GetProperty(sortExpression)
            If prop Is Nothing Then
                Throw New ArgumentException("Could not find the property " + sortExpression)
            End If
    
            Dim val As Object = prop.GetValue(obj, Nothing)
    
            Dim ret As IComparable = TryCast(val, IComparable)
            If ret Is Nothing Then
                Throw New ArgumentException("No way to compare the values as the comparable property does not implement IComparable")
            End If
    
            Return ret
        End Function
    End Class
    
    ' This is a child object that has a string property called "FullName" which
    ' is what we want to sort on
    Public Class FullNameChildObject
        Inherits SortableChildObject
    
        Private mFullName As String
    
        Protected Overrides ReadOnly Property SortExpression() As String
            Get
                SortExpression = "FullName"
            End Get
        End Property
    
        Public Property FullName() As String
            Get
                FullName = mFullName
            End Get
            Set(value As String)
                mFullName = value
            End Set
        End Property
    
    End Class
    
    请注意,它的属性必须是“SortableChildObject”-该类如下所示:

    Public Class MyObject1
    
        Private mChildObject As SortableChildObject
    
        Public Property ChildObject() As SortableChildObject
            Get
                ChildObject = mChildObject
            End Get
            Set(value As SortableChildObject)
                mChildObject = value
            End Set
        End Property
    End Class
    
    ' Implement IComparable using reflection - just look up the property to
    ' sort on based on the "SortExpression" property 
    Public MustInherit Class SortableChildObject
        Implements IComparable
    
        Protected MustOverride ReadOnly Property SortExpression() As String
    
        Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
    
            ' Make sure the object we are comparing to is also our type
            Dim oo As SortableChildObject = TryCast(obj, SortableChildObject)
            If oo Is Nothing Then
                Throw New ArgumentException("I cannot compare these two objects")
            End If
    
            ' Get the value to sort on for this object
            Dim thisVal As IComparable = GetSortableValue(Me, SortExpression)
            If thisVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for this")
            End If
    
            ' Get the value to sort on for the object we are comparing to
            Dim thatVal As IComparable = GetSortableValue(oo, oo.SortExpression)
            If thatVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for that")
            End If
    
            ' Use the IComparable implementation of the properties we are comparing
            Return thisVal.CompareTo(thatVal)
        End Function
    
        Private Function GetSortableValue(obj As Object, sortExpression As String) As IComparable
    
            Dim prop As PropertyInfo = obj.GetType().GetProperty(sortExpression)
            If prop Is Nothing Then
                Throw New ArgumentException("Could not find the property " + sortExpression)
            End If
    
            Dim val As Object = prop.GetValue(obj, Nothing)
    
            Dim ret As IComparable = TryCast(val, IComparable)
            If ret Is Nothing Then
                Throw New ArgumentException("No way to compare the values as the comparable property does not implement IComparable")
            End If
    
            Return ret
        End Function
    End Class
    
    ' This is a child object that has a string property called "FullName" which
    ' is what we want to sort on
    Public Class FullNameChildObject
        Inherits SortableChildObject
    
        Private mFullName As String
    
        Protected Overrides ReadOnly Property SortExpression() As String
            Get
                SortExpression = "FullName"
            End Get
        End Property
    
        Public Property FullName() As String
            Get
                FullName = mFullName
            End Get
            Set(value As String)
                mFullName = value
            End Set
        End Property
    
    End Class
    
    现在您必须做的是确保要排序的所有内容都继承自该类,例如,假设我们有一个具有“FullName”字符串属性的对象,它将如下所示:

    Public Class MyObject1
    
        Private mChildObject As SortableChildObject
    
        Public Property ChildObject() As SortableChildObject
            Get
                ChildObject = mChildObject
            End Get
            Set(value As SortableChildObject)
                mChildObject = value
            End Set
        End Property
    End Class
    
    ' Implement IComparable using reflection - just look up the property to
    ' sort on based on the "SortExpression" property 
    Public MustInherit Class SortableChildObject
        Implements IComparable
    
        Protected MustOverride ReadOnly Property SortExpression() As String
    
        Public Function CompareTo(obj As Object) As Integer Implements System.IComparable.CompareTo
    
            ' Make sure the object we are comparing to is also our type
            Dim oo As SortableChildObject = TryCast(obj, SortableChildObject)
            If oo Is Nothing Then
                Throw New ArgumentException("I cannot compare these two objects")
            End If
    
            ' Get the value to sort on for this object
            Dim thisVal As IComparable = GetSortableValue(Me, SortExpression)
            If thisVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for this")
            End If
    
            ' Get the value to sort on for the object we are comparing to
            Dim thatVal As IComparable = GetSortableValue(oo, oo.SortExpression)
            If thatVal Is Nothing Then
                Throw New ArgumentException("Could not get the value of the sortable property for that")
            End If
    
            ' Use the IComparable implementation of the properties we are comparing
            Return thisVal.CompareTo(thatVal)
        End Function
    
        Private Function GetSortableValue(obj As Object, sortExpression As String) As IComparable
    
            Dim prop As PropertyInfo = obj.GetType().GetProperty(sortExpression)
            If prop Is Nothing Then
                Throw New ArgumentException("Could not find the property " + sortExpression)
            End If
    
            Dim val As Object = prop.GetValue(obj, Nothing)
    
            Dim ret As IComparable = TryCast(val, IComparable)
            If ret Is Nothing Then
                Throw New ArgumentException("No way to compare the values as the comparable property does not implement IComparable")
            End If
    
            Return ret
        End Function
    End Class
    
    ' This is a child object that has a string property called "FullName" which
    ' is what we want to sort on
    Public Class FullNameChildObject
        Inherits SortableChildObject
    
        Private mFullName As String
    
        Protected Overrides ReadOnly Property SortExpression() As String
            Get
                SortExpression = "FullName"
            End Get
        End Property
    
        Public Property FullName() As String
            Get
                FullName = mFullName
            End Get
            Set(value As String)
                mFullName = value
            End Set
        End Property
    
    End Class
    
    因此,为了使用它,让我们构建一个小对象列表来进行排序,如下所示:

    Dim myObject1List As New List(Of MyObject1)
    
    Dim i As FullNameChildObject = New FullNameChildObject
    i.FullName = "B"
    
    Dim o As New MyObject1
    o.ChildObject = i
    myObject1List.Add(o)
    
    i = New FullNameChildObject
    i.FullName = "A"
    o = New MyObject1
    o.ChildObject = i
    myObject1List.Add(o)
    
    i = New FullNameChildObject
    i.FullName = "D"
    o = New MyObject1
    o.ChildObject = i
    myObject1List.Add(o)
    
    i = New FullNameChildObject
    i.FullName = "C"
    o = New MyObject1
    o.ChildObject = i
    myObject1List.Add(o)
    
    根据ChildObject属性对其进行排序非常简单,只需执行以下操作:

    Dim ret = myObject1List.OrderBy(Function(x)
                                        Return x.ChildObject
                                    End Function)
    

    这就是你需要的吗?这样做有点问题——正如你看到的,有很多地方可能会出错——例如,如果你混合了你想要比较的对象(比如,你有一个按整数排序,另一个按字符串排序)它将引发异常。

    如果我理解正确,您有一个包含对象(例如,子对象)的对象(例如,父对象)。子对象有一个字段全名,您希望按子对象全名对父对象列表进行排序

    如果是这样,那么,OrderBy()应该为您做这件事

    假设我们有一份父母名单

    父{Id=1,子{Id=1,FullName=“Jan”} 父{Id=2,子{Id=2,FullName=“Feb”} 父{Id=3,子{Id=3,FullName=“Mar”} 父{Id=4,子{Id=4,FullName=“Apr”}

    使用OrderBy()对它们进行排序

    给予

    父{Id=4,子{Id=4,FullName=“Apr”} 父{Id=2,子{Id=2,FullName=“Feb”} 父{Id=1,子{Id=1,FullName=“Jan”} 父{Id=3,子{Id=3,FullName=“Mar”}

    (下面的例子)

    hth,
    艾伦

    编辑

    请重新阅读问题。您有不同的全名属性,它们是按名称选择的(从查询字符串中选择的?)

    可以使用常规形状的表达式(请参见)按名称选择特性

    如果所选属性是IComparable(或者是IEquatable?不太确定是哪个),则OrderBy()仍将工作。这意味着只要排序字段是基本类型,就可以了。如果它们是自定义类型(对象),则需要做更多的工作

    很抱歉第一次答错了

    更多编辑

    今天是星期五,这里的速度很慢:

    好的,扩展了答案以按名称访问不同的子成员。(我使用了字段而不是属性,但两者都可以使用)。我们仍然需要知道字段的类型,但如果需要,再多做一点工作可能会删除该字段

    私有类子类
    作为整数的公共Id
    作为字符串的公共全名
    末级
    私有类父类
    作为整数的公共Id
    作为儿童的公共儿童
    末级
    从{_
    具有{_
    Key.Id=1_
    Key.Child=带有{_
    Key.Id=1_
    Key.FullName=“Jan”_
    } _
    }, _
    具有{_
    Key.Id=2_
    Key.Child=带有{_
    Key.Id=2_
    Key.FullName=“Feb”_
    } _
    }, _
    具有{_
    Key.Id=3_
    Key.Child=带有{_
    Key.Id=3_
    Key.FullName=“Mar”_
    } _
    }, _
    具有{_
    Key.Id=4_
    Key.Child=带有{_
    Key.Id=4_
    Key.FullName=“Apr”_
    } _
    } _
    }
    _
    公共子SortByChildName()
    Dim expectedparentId=New(){4,2,1,3}
    Dim sortedIds=Items.OrderBy(SelectExpression(父级,字符串)(“Child.FullName”))。[Select](函数(itm)itm.Id)
    Assert.IsTrue(ExpectedParentId.SequenceEqual(SortedDids))
    端接头
    _
    公共子SortByChildId()
    Dim expectedParentIds=New(){4,3,2,1}
    Dim sortedIds=Items.OrderBy(SelectExpression(父级,整数)(“Child.Id”)。[Select](函数(itm)itm.Id)
    Assert.IsTrue(ExpectedParentId.SequenceEqual(SortedDids))
    端接头
    公共共享函数SelectExpression(属于TItem,TField)(字段名为字符串)作为Func(属于TItem,TField)
    Dim type=GetType(TItem)
    Dim字段=字段名。拆分(“.”C)
    Dim arg As ParameterExpression=Expression.Parameter(类型为“项”)
    Dim expr As表达式=arg
    将每个字段作为字段中的字符串
    Dim fieldInfo=类型.GetField(字段)
    expr=Expression.Field(expr,fieldInfo)
    type=fieldInfo.FieldType
    下一个
    返回表达式.Lambda(很有趣