views:

40

answers:

2

I have the following setup

Class A
  property x as string
  property y as int
  property z as String

End Class

Class CollOfA
    inherits List(Of A)

End Class

What I would like is a Item property in the collection that I can say

dim c as new CollOfA
c.item("this", 2, "that")

I have tried implementing the following in CollOfA

Class CollOfA
        inherits List(Of A)

Default Public Overridable Shadows ReadOnly Property Item(ByVal x As String, ByVal y As Integer, byval z as string)
        Get
          ' what I wand to do here is something like
           ' ForEach item in me see anything matches these 3 things?

        End Get
    End Property


End Class 

I know about predicates but what I am struggling with is how to set the criteria of the predicate (i.e passing x,y,z)

Has anyone implemented something similar

+1  A: 

Here's two ways that I came up with to accomplish your question. One way uses a LINQ query syntax to filter; the second uses a custom object to hold your predicate parameters and then uses that object to perform the filter.

Using the LINQ syntax in your Item property:

Default Public Overridable Shadows ReadOnly Property Item(ByVal x As String, ByVal y As Integer, ByVal z As String) As IEnumerable(Of A)
    Get
        Return (From theA In Me
                Where (theA.x = x And theA.y = y And theA.z = z)
                Select theA)

    End Get
End Property

The other way would be to create a PredicateParameter class to hold your parameters and also a delegated method that is used to execute the filter. I saw this on an MSDN comment - here's the link. Here's the class:

Class PredicateParams

    Public Sub New(ByVal theA As A)
        Criteria = theA
    End Sub

    Public Property Criteria As A

    Public Function IsMatch(ByVal theA As A) As Boolean
        Return (theA.x = Criteria.x And theA.y = Criteria.y And theA.z = Criteria.z)
    End Function

End Class

And here's the property that is in the CollOfA class that uses it:

Public Overridable Shadows ReadOnly Property ItemPred(ByVal x As String, ByVal y As Integer, ByVal z As String) As IEnumerable(Of A)
    Get
        Dim predA As New A
        predA.x = x
        predA.y = y
        predA.z = z

        Dim pred As New PredicateParams(predA)

        Return Me.FindAll(AddressOf pred.IsMatch)
    End Get

End Property

Lastly, here's a console runner to test this.

Sub Main()
    Dim mycoll As New CollOfA()


    For index = 1 To 100
        Dim anA As New A()
        anA.x = (index Mod 2).ToString()
        anA.y = index Mod 4
        anA.z = (index Mod 3).ToString()
        mycoll.Add(anA)
    Next

    Dim matched As IEnumerable(Of A) = mycoll.Item("1", 3, "2")
    Dim matched2 As IEnumerable(Of A) = mycoll.ItemPred("1", 3, "2")

    Console.WriteLine(matched.Count.ToString())  'output from first search
    Console.WriteLine(matched2.Count.ToString()) 'output from second search (s/b same)
    Console.ReadLine()

End Sub

Hopefully this helps. There may be a more elegant way to do this, but I didn't see one. (BTW, I generally work with C#, so my VB.NET is a little rusty.)

David Hoerster
A: 

If your class A is simple enough, you may be able to get away with a one-line default property getter and the Find method of your List, something like this:

Public Class CollOfA
    Inherits List(Of A)

    Default Public Overloads ReadOnly Property Item(ByVal x As String, ByVal y As Integer, ByVal z As String) As A
        Get
            Return Find(Function(a As A) (((a.x = x) AndAlso (a.y = y)) AndAlso (a.z = z)))
        End Get
    End Property
End Class

I did this in Visual Studio 2008, so I don't know how it'll work in other versions.

Curt