如何使用 属性 项目 implement/override 为自定义 Collection Class 保护 List.Contains()
How to implement/override Protected List.Contains() for a custom Collection Class using a property of item
我不完全确定我在上面的标题中的措辞是否正确。我想解释它的最简单方法是将代码放在下面以供参考,然后给出我想要的预期行为。
Public Class Domino
Public ReadOnly MinimumSideValue As Integer = 0
Public ReadOnly MaximumSideValue As Integer = 6
Public Property key As Integer
Public Property Side1 As Integer
Public Property Side2 As Integer
Public Sub New(side1Value As Integer, side2Value As Integer)
Me.Side1 = side1Value
Me.Side2 = side2Value
' Key should be a two digit number. side values 5 and 1 -> 51
Me.key = Integer.Parse(Side1.ToString & Side2.ToString)
End Sub
Public Overrides Function ToString() As String
Return Convert.ToString(Me.key)
End Function
End Class
Public Class DominoCollection
Inherits System.Collections.CollectionBase
Public Sub AddDomino(newDomino As Domino)
' Not sure if I should be calling Contains on the Protected List object
If Not List.Contains(newDomino) Then
List.Add(newDomino)
End If
End Sub
Public Function Contains(objDomino as Domino) As Boolean
' Need to check if a domino that has the same key already exists
Dim found As Boolean = False
For i = 0 To List.Count - 1 'This will fail if the list is empty...
If DirectCast(List.Item(i), Domino).key = objDomino.key Then found = True
Next
Return found
End Function
End Class
第一个代码清单是 class,它将创建多个实例。第二个 class 是 collection,它将包含第一个 class 的实例。 collection 不应包含重复项。因此,当我从 CollectionBase 调用 built-in protected List
object 上的 contains 方法时,我希望它搜索项目列表以查找具有相同值的重复项 key
属性 第一个 class。
我不完全确定我是否可以重写 List.Contains 方法,因为它是一个受保护的 object and/or 如果我真的应该创建自己的 contains 方法。我尝试创建自己的 .Contains 方法,但如果列表为空则失败。
编辑
我知道我的代码不是用 C# 编写的。但是,由于它是 .NET,因此 C# 答案的帮助与 VB 一样多。
编辑:修改后的代码
在看到下面的一些解决方案后,我得到了以下的解决方案,目前看来它可以按我的要求工作。但是我不确定我是否正确实施了 Item
属性。我还没有测试它,因为我还没有达到能够在应用程序的其余部分使用它的地步,我只是想降低一个框架。
Friend Class DominoCollection
Private domCol As Dictionary(Of Integer, Domino)
Public ReadOnly Property Keys As System.Collections.Generic.Dictionary(Of Integer, Domino).KeyCollection
Get
Return domCol.Keys
End Get
End Property
Public ReadOnly Property Values As System.Collections.Generic.Dictionary(Of Integer, Domino).ValueCollection
Get
Return domCol.Values
End Get
End Property
Default Public Property Item(DominoKey As Integer) As Domino
Get
If domCol.ContainsKey(DominoKey) Then
Return domCol.Item(DominoKey)
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Get
Set(value As Domino)
If domCol.ContainsKey(DominoKey) Then
domCol.Item(DominoKey) = value
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Set
End Property
Default Public Property Item(domino As Domino) As Domino
Get
If domCol.ContainsKey(domino.key) Then
Return domCol.Item(domino.key)
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Get
Set(value As Domino)
If domCol.ContainsKey(domino.key) Then
domCol.Item(domino.key) = value
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Set
End Property
Public Sub New()
domCol = New Dictionary(Of Integer, Domino)
End Sub
Public Sub Add(dom As Domino)
If Not domCol.ContainsKey(dom.key) Then
domCol.Add(dom.key, dom)
End If
End Sub
Public Function Contains(dom As Domino) As Boolean
Return domCol.ContainsKey(dom.key)
End Function
' flexibility:
Public Function Remove(dom As Domino) As Boolean
If domCol.ContainsKey(dom.key) Then
domCol.Remove(dom.key)
Return True
Else
Return False
End If
End Function
Public Function Remove(key As Integer) As Boolean
If domCol.ContainsKey(key) Then
domCol.Remove(key)
Return True
Else
Return False
End If
End Function
Public Function Count() As Integer
Return domCol.Count
End Function
Public Sub Clear()
domCol.Clear()
End Sub
End Class
是的,您绝对应该继承通用集合 class 或实现通用集合接口。
我不确定 VB 的确切语法,但我认为您希望使用带有 lambda 的 Linq 扩展 Any
而不是 List.Contains
。我认为它是这样的:
List.Any(Function(d as Domino) d.key = newDomino.key)
如果 List
中的任何元素与键匹配,这将 return 为真。
鉴于 Domino.Key
的核心重要性,我认为使用字典的 class 会使事情变得最简单。由于您的代码一直在寻找它来确定 Domino
对象是否存在等,因此字典将有助于检测并防止重复等
Friend Class DominoCollection
Private mcol As Dictionary(Of Integer, Domino)
Public Sub New()
mcol = New Dictionary(Of Integer, Domino)
End Sub
Public Sub Add(dom As Domino)
If mcol.ContainsKey(dom.key) = False Then
mcol.Add(dom.key, dom)
' optional: replace - dont know if this is needed
Else
mcol(dom.key) = dom
End If
End Sub
Public Function Contains(dom As Domino) As Boolean
Return mcol.ContainsKey(dom.key)
End Function
' flexibility:
Public Function Remove(dom As Domino) As Boolean
If mcol.ContainsKey(dom.key) Then
mcol.Remove(dom.key)
Return True
End If
Return False
End Function
Public Function Remove(key As Integer) As Boolean
If mcol.ContainsKey(key) Then
mcol.Remove(key)
Return True
End If
Return False
End Function
End Class
对于一个项目和项目:
Public Function Item(key As Integer) As Domino
Return mcol(key)
End Function
Public Function Items() As List(Of Domino)
Return New List(Of Domino)(mcol.Values)
End Function
Items
隐藏了迭代通常需要的 KeyValuePair
并允许您对(需要的)集合做一个简单的 For/Each 循环:
Dim doms As New DominoCollection
doms.Add(New Domino(1, 2))
doms.Add(New Domino(2, 3))
doms.Add(New Domino(4, 6))
For Each d As Domino In doms.Items
Console.WriteLine("s1:{0} s2:{1} k:{2}", d.Side1, d.Side2, d.key.ToString)
Next
输出
s1:1 s2:2 k:12
s1:2 s2:3 k:23
s1:4 s2:6 k:46
我不完全确定我在上面的标题中的措辞是否正确。我想解释它的最简单方法是将代码放在下面以供参考,然后给出我想要的预期行为。
Public Class Domino
Public ReadOnly MinimumSideValue As Integer = 0
Public ReadOnly MaximumSideValue As Integer = 6
Public Property key As Integer
Public Property Side1 As Integer
Public Property Side2 As Integer
Public Sub New(side1Value As Integer, side2Value As Integer)
Me.Side1 = side1Value
Me.Side2 = side2Value
' Key should be a two digit number. side values 5 and 1 -> 51
Me.key = Integer.Parse(Side1.ToString & Side2.ToString)
End Sub
Public Overrides Function ToString() As String
Return Convert.ToString(Me.key)
End Function
End Class
Public Class DominoCollection
Inherits System.Collections.CollectionBase
Public Sub AddDomino(newDomino As Domino)
' Not sure if I should be calling Contains on the Protected List object
If Not List.Contains(newDomino) Then
List.Add(newDomino)
End If
End Sub
Public Function Contains(objDomino as Domino) As Boolean
' Need to check if a domino that has the same key already exists
Dim found As Boolean = False
For i = 0 To List.Count - 1 'This will fail if the list is empty...
If DirectCast(List.Item(i), Domino).key = objDomino.key Then found = True
Next
Return found
End Function
End Class
第一个代码清单是 class,它将创建多个实例。第二个 class 是 collection,它将包含第一个 class 的实例。 collection 不应包含重复项。因此,当我从 CollectionBase 调用 built-in protected List
object 上的 contains 方法时,我希望它搜索项目列表以查找具有相同值的重复项 key
属性 第一个 class。
我不完全确定我是否可以重写 List.Contains 方法,因为它是一个受保护的 object and/or 如果我真的应该创建自己的 contains 方法。我尝试创建自己的 .Contains 方法,但如果列表为空则失败。
编辑
我知道我的代码不是用 C# 编写的。但是,由于它是 .NET,因此 C# 答案的帮助与 VB 一样多。
编辑:修改后的代码
在看到下面的一些解决方案后,我得到了以下的解决方案,目前看来它可以按我的要求工作。但是我不确定我是否正确实施了 Item
属性。我还没有测试它,因为我还没有达到能够在应用程序的其余部分使用它的地步,我只是想降低一个框架。
Friend Class DominoCollection
Private domCol As Dictionary(Of Integer, Domino)
Public ReadOnly Property Keys As System.Collections.Generic.Dictionary(Of Integer, Domino).KeyCollection
Get
Return domCol.Keys
End Get
End Property
Public ReadOnly Property Values As System.Collections.Generic.Dictionary(Of Integer, Domino).ValueCollection
Get
Return domCol.Values
End Get
End Property
Default Public Property Item(DominoKey As Integer) As Domino
Get
If domCol.ContainsKey(DominoKey) Then
Return domCol.Item(DominoKey)
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Get
Set(value As Domino)
If domCol.ContainsKey(DominoKey) Then
domCol.Item(DominoKey) = value
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Set
End Property
Default Public Property Item(domino As Domino) As Domino
Get
If domCol.ContainsKey(domino.key) Then
Return domCol.Item(domino.key)
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Get
Set(value As Domino)
If domCol.ContainsKey(domino.key) Then
domCol.Item(domino.key) = value
Else
Throw New KeyNotFoundException(String.Format("Cannot find key {0} in internal collection"))
End If
End Set
End Property
Public Sub New()
domCol = New Dictionary(Of Integer, Domino)
End Sub
Public Sub Add(dom As Domino)
If Not domCol.ContainsKey(dom.key) Then
domCol.Add(dom.key, dom)
End If
End Sub
Public Function Contains(dom As Domino) As Boolean
Return domCol.ContainsKey(dom.key)
End Function
' flexibility:
Public Function Remove(dom As Domino) As Boolean
If domCol.ContainsKey(dom.key) Then
domCol.Remove(dom.key)
Return True
Else
Return False
End If
End Function
Public Function Remove(key As Integer) As Boolean
If domCol.ContainsKey(key) Then
domCol.Remove(key)
Return True
Else
Return False
End If
End Function
Public Function Count() As Integer
Return domCol.Count
End Function
Public Sub Clear()
domCol.Clear()
End Sub
End Class
是的,您绝对应该继承通用集合 class 或实现通用集合接口。
我不确定 VB 的确切语法,但我认为您希望使用带有 lambda 的 Linq 扩展 Any
而不是 List.Contains
。我认为它是这样的:
List.Any(Function(d as Domino) d.key = newDomino.key)
如果 List
中的任何元素与键匹配,这将 return 为真。
鉴于 Domino.Key
的核心重要性,我认为使用字典的 class 会使事情变得最简单。由于您的代码一直在寻找它来确定 Domino
对象是否存在等,因此字典将有助于检测并防止重复等
Friend Class DominoCollection
Private mcol As Dictionary(Of Integer, Domino)
Public Sub New()
mcol = New Dictionary(Of Integer, Domino)
End Sub
Public Sub Add(dom As Domino)
If mcol.ContainsKey(dom.key) = False Then
mcol.Add(dom.key, dom)
' optional: replace - dont know if this is needed
Else
mcol(dom.key) = dom
End If
End Sub
Public Function Contains(dom As Domino) As Boolean
Return mcol.ContainsKey(dom.key)
End Function
' flexibility:
Public Function Remove(dom As Domino) As Boolean
If mcol.ContainsKey(dom.key) Then
mcol.Remove(dom.key)
Return True
End If
Return False
End Function
Public Function Remove(key As Integer) As Boolean
If mcol.ContainsKey(key) Then
mcol.Remove(key)
Return True
End If
Return False
End Function
End Class
对于一个项目和项目:
Public Function Item(key As Integer) As Domino
Return mcol(key)
End Function
Public Function Items() As List(Of Domino)
Return New List(Of Domino)(mcol.Values)
End Function
Items
隐藏了迭代通常需要的 KeyValuePair
并允许您对(需要的)集合做一个简单的 For/Each 循环:
Dim doms As New DominoCollection
doms.Add(New Domino(1, 2))
doms.Add(New Domino(2, 3))
doms.Add(New Domino(4, 6))
For Each d As Domino In doms.Items
Console.WriteLine("s1:{0} s2:{1} k:{2}", d.Side1, d.Side2, d.key.ToString)
Next
输出
s1:1 s2:2 k:12
s1:2 s2:3 k:23
s1:4 s2:6 k:46