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.)