我提供了以下字符串表达式:
“ChildObject.FullName”...其中ChildObject是MyObject1类型的实例属性。
ChildObject有一个名为“FullName”的属性,我想根据这个子属性“FullName”值对“MyObject1”类型的集合进行排序。
我可以直接在MyObject1上对属性进行整天这样做,但是当我在子实例上进行操作时遇到2个挑战并且我无法使所有部分工作。主要的2个挑战是:
对于上面的#2,我可以使用Reflection来获取子属性的类型,但我无法全部工作。我有下面的内容,它编译并运行,但不会有任何不同的排序:
'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方法, 为我提供了我需要的'FullName'信息。所以代码必须关闭,但它仍然不起作用。
关于如何实现这一目标的任何想法?我想要阻止的是硬编码子类型上的一系列“If”块,然后将其类型硬编码为sort或OrderBy方法。
谢谢!
答案 0 :(得分:2)
如果我正确地理解了这个问题(免责声明 - 这是我写过的第一个vb.net代码,它可能不是最好的,从语法上来说 - 我先用c#编写它),你可以通过以下方式实现这一点:做以下事情......
让我们说你的MyObject1看起来像这样:
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
请注意,它的属性必须是" SortableChildObject" - 那个班级看起来像这样:
' 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
现在您必须做的是确保您要排序的所有内容都继承自此类,例如说我们有一些具有" FullName"它上面的字符串属性,它看起来像这样:
' 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)
这就是你需要的吗?这样做有点问题 - 正如你所看到的那样,有很多地方可能会出现问题 - 例如,如果你混合了你想要比较的对象(例如,你有一个对整数进行排序的对象)它将引发异常。
答案 1 :(得分:1)
如果我理解正确,你有一个对象(比如,Parent),它包含一个对象(比如Child)。 Child有一个FullName字段,您希望按子FullName对父项列表进行排序。
如果是,那么 OrderBy()应该为你做。
假设我们有一个父母列表
父{Id = 1,Child = {Id = 1,FullName =“Jan”}} 父{Id = 2,Child = {Id = 2,FullName =“Feb”}} 父{Id = 3,Child = {Id = 3,FullName =“Mar”}} 父{Id = 4,Child = {Id = 4,FullName =“Apr”}}
使用OrderBy()
对它们进行排序Dim sorted = Items.OrderBy(Function(itm) itm.Child.FullName)
给出
父{Id = 4,Child = {Id = 4,FullName =“Apr”}} 父{Id = 2,Child = {Id = 2,FullName =“Feb”}} 父{Id = 1,Child = {Id = 1,FullName =“Jan”}} 父{Id = 3,Child = {Id = 3,FullName =“Mar”}}
(以下示例)
hth,
艾伦。
修改强>
重新阅读问题。您有不同的 FullName 属性,这些属性是按名称选择的(来自查询字符串?)
您可以使用表达式(请参阅How can I create a dynamic Select on an IEnumerable<T> at runtime?)按名称选择属性以获取常规形状。
如果所选属性是IComparable(或者它是IEquatable?不太确定哪个)那么OrderBy()仍然可以工作。这意味着只要排序字段是基本类型就可以了。如果它们是自定义类型(对象),您将需要做更多的工作......
对于第一个错误答案感到抱歉。
更多编辑
这是星期五,在这里缓慢:?
好的,扩大了答案,通过名字访问不同的儿童成员。 (我使用的是Fields而不是Properties,但它们都可以使用)。我们仍然需要知道字段的类型,但可能会删除更多的工作(如果需要)。
Private Class Child
Public Id As Integer
Public FullName As String
End Class
Private Class Parent
Public Id As Integer
Public Child As Child
End Class
Private Items As New List(Of Parent)() From { _
New Parent() With { _
Key .Id = 1, _
Key .Child = New Child() With { _
Key .Id = 1, _
Key .FullName = "Jan" _
} _
}, _
New Parent() With { _
Key .Id = 2, _
Key .Child = New Child() With { _
Key .Id = 2, _
Key .FullName = "Feb" _
} _
}, _
New Parent() With { _
Key .Id = 3, _
Key .Child = New Child() With { _
Key .Id = 3, _
Key .FullName = "Mar" _
} _
}, _
New Parent() With { _
Key .Id = 4, _
Key .Child = New Child() With { _
Key .Id = 4, _
Key .FullName = "Apr" _
} _
} _
}
<TestMethod> _
Public Sub SortByChildName()
Dim expectedParentIds = New () {4, 2, 1, 3}
Dim sortedIds = Items.OrderBy(SelectExpression(Of Parent, String)("Child.FullName")).[Select](Function(itm) itm.Id)
Assert.IsTrue(expectedParentIds.SequenceEqual(sortedIds))
End Sub
<TestMethod> _
Public Sub SortByChildId()
Dim expectedParentIds = New () {4, 3, 2, 1}
Dim sortedIds = Items.OrderBy(SelectExpression(Of Parent, Integer)("Child.Id")).[Select](Function(itm) itm.Id)
Assert.IsTrue(expectedParentIds.SequenceEqual(sortedIds))
End Sub
Public Shared Function SelectExpression(Of TItem, TField)(fieldNames As String) As Func(Of TItem, TField)
Dim type = GetType(TItem)
Dim fields = fieldNames.Split("."C)
Dim arg As ParameterExpression = Expression.Parameter(type, "item")
Dim expr As Expression = arg
For Each field As String In fields
Dim fieldInfo = type.GetField(field)
expr = Expression.Field(expr, fieldInfo)
type = fieldInfo.FieldType
Next
Return Expression.Lambda(Of Func(Of TItem, TField))(expr, arg).Compile()
End Function