1

Framework2.0でVB.NETを使用しています。GenericList<>を2つのプロパティですばやくグループ化することを検討しています。この例のために、CustomerId、ProductId、およびProductCountのプロパティを持つOrderタイプのリストがあるとします。VB.NETでCustomerIdとProductIdによってグループ化されたProductCountsの平均を取得するにはどうすればよいですか?

残念ながら、これをDBレベルで行うことはできません(これは簡単だったでしょう)。また、Framewwork2.0のImとしてLINQまたはLambadaを使用することはできません。したがって、VB.netのアプリケーションレベルでこれを行う必要があります。リストはCustomerIdとProductIdでソートされて返されるので、いくつかのループでsIの平均値を作成できるはずですが、これを行うためのよりクリーンな方法が必要ですか?

4

1 に答える 1

1

この種の問題は、C# と VB.NET で LINQ が導入された理由の好例です。.NET 3.5 以降では、LINQ は、この問題を解決するために探している "よりクリーンな方法" を提供します。

残念ながら、.NET 2.0 を使用しているため、多かれ少なかれ「手動」で問題を解決する必要があります。ただし、探している機能を適切に定義されたクラスとメソッドにカプセル化することで、クリーンなコードを書くことができます。これは、LINQ の利点の 1 つ (ただし、これだけではありません) です。つまり、必要な機能をクリーンで宣言的な方法でカプセル化します。

開始するためのサンプル コードを次に示します。

'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()

明らかに、コードをよりよく再利用するために、この抽象化の道を歩み続けることができますが、これは良いスタートになると思います。

于 2010-08-18T13:32:01.640 に答える