创建一个集合对象

6
这不是一道作业题,尽管情境很离奇。我只是为了简化例子而替换了我正在使用的真实对象。这里有一个链接可以帮助你入门:This,但我不确定该如何继续。 我正在尝试编写一个包含集合的类,并且我在IEnumeratorIEnumerable的世界中迷失了方向,这是我很新的领域(甚至不确定我是否走上了正确的道路)。假设我有一个类:
Public Class BakedBean
    Private Shape As String
    Private Variety As String
    Private Flavour As String
    'etc
End Class

还有一个表示一组 BakedBean 的类:

Public Class TinOfBeans
    '?
End Class

我希望能够在 TinOfBeans 类中以集合的形式获取 Beans,这样我就可以进行一些调用,但不必绑定到特定的集合类型:

Dim myTin As New TinOfBeans()
myTin.Add(New BakedBean(...))

For Each bean As BakedBean in myTin
    '...
Next

myTin(0).Flavour = "beany"

我一直在研究IEnumerableIEnumerator,目前已经了解了这么多,但我现在非常迷茫:

BakedBean类

Public Class BakedBean
    Private Shape As String
    Private Variety As String
    Private Flavour As String
    'etc
End Class

BeansEnumerator 类

Public Class BeansEnumerator
    Implements IEnumerator

    Private Position As Integer = -1

    Public ReadOnly Property Current As Object Implements System.Collections.IEnumerator.Current
        Get
            '???
        End Get
    End Property

    Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
        '???
    End Function

    Public Sub Reset() Implements System.Collections.IEnumerator.Reset
        Position = -1
    End Sub
End Class

TinOfBeans类

Public Class TinOfBeans
    Implements IEnumerable

    Private beansEnum As BeansEnumerator

    Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return beansEnum
    End Function
End Class

目前为止,我已经陷入了困境,不知道该怎么继续下去(或者,正如我一开始所说的那样,这是否是正确的方法)。有什么建议吗?


让我看看是否理解您的意思。您想要一个类,它是一个列表吗? - Alexandre
我想要一个类,它是一个集合,不一定是一个列表。 - Kai
请问您为什么需要这个?标准集合有什么问题吗? - Alexandre
当然,我可以在我的TinOfBeans类中添加一个Private beans As List(Of BakedBeans),并通过属性公开它,但那样我就永远被绑定到了一个List上。如果我以后需要将其更改为Dictionary或其他什么(世界需要更多的豆子字典!),我就有破坏所有涉及它的代码的风险。我不能完全放弃TinOfBeans类并用List(Of BakedBeans)替换整个类,因为它将具有List没有的其他方法(例如Cook())。 - Kai
我明白了,感谢提供的信息。虽然我不知道如何做到这一点,但我找到了这个链接,可能会有用:http://msdn.microsoft.com/en-us/library/xth2y6ft(v=vs.71).aspx。希望这能帮到你。 - Alexandre
2个回答

8
你正在把这件事情搞得太难了。.Net已经通过泛型提供了你所需的精确类。

我想要能够...像这样进行调用:

Dim myTin As New TinOfBeans()
myTin.Add(New BakedBean(...))

For Each bean As BakedBean in myTin
    '...
Next

myTin(0).Flavour = "beany"

好的,以下是方法:

Dim myTin As New List(Of BakedBean)()
myTin.Add(New BakedBean(...))

For Each bean As BakedBean in myTin 
   '...
Next

myTin(0).Flavour = "beany"

每一行代码都非常精确,让通用集合为您完成工作吧。
您似乎也对IEnumerable感到困惑,而我还有一个要求需要实现:
“在不绑定特定集合类型的情况下进行调用...”
我们可以用一种技术来解决这两个问题。让我们定义一个接受Bean集合的方法:
Public Sub CookBeans(ByVal beans As List(Of BakedBean))

然而,这并不处理数组、迭代器或其他BakedBean集合类型。这里的答案是IEnumerable:

Public Sub CookBeans(BvVal beans As IEnumerable(Of BakedBean))
   For Each bean As BakedBean In beans
      Cook(bean)
   Next 
End Sub

这次我包含了一个方法的实现示例,以便您可以看到它的工作原理。重要的是要理解这个方法将允许您调用它并传递一个数组、列表、迭代器或任何其他BakedBean集合。
这是因为 List(Of BakedBean) 是 (或者更确切地说,实现了) IEnumerable(Of BakedBean)。BakedBean 数组和其他 .Net 集合也是如此。IEnumerable 是所有集合的根接口。您可以在内存中拥有一个具体的 List(Of BakedBean) 对象,但是使用 IEnumerable(Of BakedBean) 定义您的方法参数和返回类型,如果您决定将该 List 对象更改为其他内容,那些方法仍然会起作用。
您还可以返回 IEnumerable:
Public Function GetPintos(ByVal beans As IEnumerable(Of BakedBean)) As IEnumerable(Of BakedBean)
    Dim result As IEnumerable(Of BakedBean)
    result = beans.Where(Function(bean) bean.Variety = "pinto")
    Return result
End Function

如果你需要将IEnumerable转换为列表,这很容易:

Dim beans As List(Of BakedBeans) = '... get beans from somewhere

Dim pintos As List(Of BakedBeans) = GetPintos(beans).ToList()
CookBeans(pintos)

"IEnumerable是所有集合的根接口。" 我真的没有想到这一点。看起来正是我需要的,因为它不会限制我使用特定的集合。太完美了,谢谢。 - Kai
1
@Kai 在这里要小心:该声明中存在一些夸张之词。它是框架中提供的所有集合的根接口,但我见过野外使用封装数组或列表而没有实现该接口的自定义集合。这是不好的做法,但确实会发生。 - Joel Coehoorn
我会记住的。这应该满足我的需求,谢谢。 - Kai
@JoelCoehoorn 一个问题,你放置的所有方法,例如:Public Sub CookBeans(BvVal beans As IEnumerable(Of BakedBean)),GetPintos应该仍然属于BakedBean类还是作为存储私有列表对象的集合类分离? - Arie

1

我认为你可能把事情复杂化了。除非你真的想学习如何使用IEnumerable,否则只需要继承一个list。

Public Class TinOfBeans
    Inherits List(Of BakedBean)

End Class

或者在 Tin 内部有一个列表

Public Class TinOfBeans
    Public Property Beans As New List(Of BakedBean)

End Class

1
或者干脆不要继承,需要时直接写出 List(Of BakedBean) - Joel Coehoorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接