Этот тип проблемы является отличным примером того, почему LINQ был представлен в C # и VB.NET. В .NET 3.5 и более поздних версиях LINQ предоставляет «более чистый путь», который вы ищете для решения этой проблемы.
К сожалению, поскольку вы используете .NET 2.0, вам придется решать проблему более или менее «вручную». Однако вы все равно можете писать чистый код, инкапсулируя нужную функциональность в четко определенные классы и методы. Это одно (но не единственное) из преимуществ LINQ, то есть то, что он инкапсулирует ожидаемую функциональность чистым, декларативным образом.
Вот пример кода, с которого можно начать:
'The AggregateItem and AggregateItems classes will help encapsulate the '
'the functionality you are looking for.'
Public Class AggregateItem
Public Property GroupByProperty1 As Integer ' Get/Set code...'
Public Property GroupByProperty2 As Integer ' Get/Set code...'
Public Property Values As List(Of Double) = New List(Of Double()() _
' Get/Set code...'
Public Function GetAverage() As Double
'Code to calculate and return Average...'
End Function
End Class
Public Class AggregateItems
Public Property AggregateItemList As List(Of AggregateItem) = _
New List(Of AggregateItem)() ' Get/Set code...'
Public Sub InsertAggregateItem(groupByProperty1 As Integer, _
groupByProperty2 As Integer, _
value As Double)
Dim aiExisting As AggregateItem
aiExisting = GetMatchingAggregateItem(groupByProperty1, _
groupByProperty2)
If Not aiExisting Is Nothing Then
aiExisting.Values.Add(value)
Else
aiExisting = New AggregateItem
aiExisting.GroupByProperty1 = groupByProperty1
aiExisting.GroupByProperty2 = groupByProperty2
aiExisting.Values.Add(value)
AggregateItemList.Add(aiExisting)
End Sub
Private Function GetMatchingAggregateItem(groupByProperty1 As Integer, _
groupByProperty2 As Integer) _
As AggregateItem
Dim aiMatch As AggregateItem = Nothing
For Each ag As AggregateItem in AggregateItemList
If ag.GroupByProperty1 = groupByProperty1 AndAlso _
ag.GroupByProperty2 = groupByProperty2 Then
aiMatch = ag
Exit For
End If
Next
Return aiMatch
End Function
Enc Class
'Then, to consume these classes....'
Public Module MyProgram
Public Sub Main()
Dim aItems As New AggregateItems()
'Say you have List(Of Order) named listOfOrders'
'We will loop through that list, insert the grouping IDs and values'
'into our AggregateItems object'
For Each o As Order In listOfOrders
aItems.InsertAggregateItem(o.OrderId, o.ProductId, o.ProductCount)
Next
'Now we can loop through aItems to cleanly get the average: '
For Each ai As AggregateItem in aItems.AggregateItemsList
Console.WriteLine("Order: {0} Product: {1} Average: {2}", _
ai.GroupByProperty1, ai.GroupByProperty2, _
ai.GetAverage())
Next
End Sub
End Module
Хорошая особенность вставки ваших данных в хорошо инкапсулированные классы заключается в том, что код потребления очень лаконичен и прост для понимания. Кроме того, поскольку ваши данные уже объединены в класс AggregateItem
, вы можете легко расширить этот класс с помощью нескольких методов, таких как GetSum()
или GetMax()
.
.
Очевидно, что вы могли бы продолжить этот путь абстракции, чтобы лучше повторно использовать свой код, но я думаю, что это дает вам хорошее начало.