通过从众多 .NET Framework 集合类之一继承,并添加实现您自己的自定义功能的代码,可以创建您自己的集合类。在本主题中,您将使用继承来创建一个从 CollectionBase 继承的简单的强类型集合。
.NET Framework 在 System.Collections 命名空间中提供了若干集合类型的类。其中有些类(如 Stack、Queue 和 Dictionary)是已经实现以完成特定任务的专用类。而有些类(如 CollectionBase 和 DictionaryBase)则是已经具有某些基本功能,但将大部分实现工作都留给开发人员完成的 MustInherit (abstract) 类。
CollectionBase 类已经具有 Clear 方法和 Count 属性的实现,它维护一个称为 List 的 Protected 属性,并将该属性用于内部存储和组织。其他方法(如 Add 和 Remove)以及 Item 属性需要实现。
在该演练中,您使用 CollectionBase 类创建一个称为 WidgetCollection 的类。它是一个只接受小部件的集合,并且将其成员作为 Widget 类型公开,而不是接受对象并将成员作为 Object 类型公开。您然后实现将小部件添加到集合中和移除适当索引处的小部件的方法,您还实现 Item 属性以返回适当索引处的小部件对象。
创建类
第一步是创建要放入到 WidgetCollection 中的 Widget 类。
创建 Widget 类
- 打开一个新的 Windows 应用程序并将其命名为 WidgetProject。从“项目”菜单中选择“添加类”。在“添加新项”对话框中,将该类命名为 Widget.vb 以用于 Visual Basic,将该类命名为 Widget.cs 以用于 Visual C#。
Widget 类的代码编辑器打开。
- 将一个公共的 Name 变量添加到 Widget 类。代码看起来应类似于以下形式:
' Visual Basic
Public Class Widget
Public Name as String
End Class
// C#
public class Widget
{
public string Name;
public Widget()
{
}
} - 从“文件”菜单中选择“全部保存”。
现在已创建了一个 Widget 类,它将与下一步要创建的 WidgetCollection 类一起使用。Widget 类是一个简单的类,用于说明强类型的集合如何工作。下一步是创建 WidgetCollection 类。
创建 WidgetCollection 类
- 从“项目”菜单中选择“添加类”。在“添加新项”对话框中,将该类命名为 WidgetCollection.vb 以用于 Visual Basic,将该类命名为 WidgetCollection.cs 以用于 Visual C#。WidgetCollection 类的代码编辑器打开。
- 在代码编辑器中,添加使该类从 CollectionBase 继承的代码,如下例所示:
' Visual Basic
Public Class WidgetCollection
Inherits System.Collections.CollectionBase
End Class
// C#
public class WidgetCollection : System.Collections.CollectionBase
{
} - 从“文件”菜单中选择“全部保存”。
现在已创建了 WidgetCollection 类。因为该类是从 CollectionBase 继承的,所以它已经实现了许多集合功能。有清除集合的 Clear 方法和跟踪当前成员数的 Count 属性。此外,还有一个称为 List 的 Protected 对象用于跟踪小部件。但没有 Add 方法、Remove 方法和 Item 属性。它们的实现都留给开发人员来完成。
实现 Add 和 Remove 方法
现在您将实现 Add 方法,以便 WidgetCollection 只添加 Widget 对象。
实现 Add 方法
- 将下面的代码添加到您的 WidgetCollection 类中,在 C# 中添加到 class 语句下,而在 Visual Basic 中则添加到 Inherits 语句下:
' Restricts to Widget types, items that can be added to the collection.
Public Sub Add(ByVal awidget As Widget)
' Invokes Add method of the List object to add a widget.
List.Add(aWidget)
End Sub
// C#
// Restricts to Widget types, items that can be added to the collection
public void Add(Widget aWidget)
{
List.Add(aWidget);
}在该方法中,您将通过 Add 方法所带的参数添加到 List 对象中的项限制为 Widget 类型。尽管 List 对象可以接受任何类型的对象,但该方法禁止添加 Widget 类型以外的任何对象,并充当 List 对象的“包装”。
- 从“文件”菜单中选择“全部保存”。
现在您有了将小部件添加到集合中的方法。您现在必须实现移除这些小部件的方法。通过与创建 Add 方法类似的方式来做到这一点,创建一个接受索引作为参数并反过来调用 List.RemoveAt 方法的 Remove 方法。
实现 Remove 方法
- 在
Add 方法的下方添加下列代码: ' Visual Basic
Public Sub Remove(ByVal index as Integer)
' Check to see if there is a widget at the supplied index.
If index > Count - 1 Or index < 0 Then
' If no widget exists, a messagebox is shown and the operation is
' cancelled.
System.Windows.Forms.MessageBox.Show("Index not valid!")
Else
' Invokes the RemoveAt method of the List object.
List.RemoveAt(index)
End If
End Sub
// C#
public void Remove(int index)
{
// Check to see if there is a widget at the supplied index.
if (index > Count - 1 || index < 0)
// If no widget exists, a messagebox is shown and the operation
// is cancelled.
{
System.Windows.Forms.MessageBox.Show("Index not valid!");
}
else
{
List.RemoveAt(index);
}
}该方法接受整数值作为索引参数。如果该值有效,它将被传递给 List 对象的 RemoveAt 方法,从而从集合中移除位于所指示的索引处的项。
- 从“文件”菜单中选择“全部保存”。
实现 Item 属性
为完成基本的集合功能,您需要实现最后一部分,即 Item 属性。Item 属性使您可以通过引用索引获取集合中某一对象的引用。鉴于您已经具有将成员添加到集合的 Add 方法,在该演示中,Item 将为 ReadOnly 属性,但在其他上下文中不必如此。由于 C# 不允许属性带参数,所以如果使用的是 C# 则需要将 Item 作为方法实现。
实现 Item 属性
- 在
Sub Remove 方法下方添加下列代码: ' This line declares the Item property as ReadOnly, and
' declares that it will return a Widget object.
Public ReadOnly Property Item(ByVal index as Integer) As Widget
Get
' The appropriate item is retrieved from the List object and
' explicitly cast to the Widget type, then returned to the
' caller.
Return CType(List.Item(index), Widget)
End Get
End Property
// C#
public Widget Item(int Index)
{
// The appropriate item is retrieved from the List object and
// explicitly cast to the Widget type, then returned to the
// caller.
return (Widget) List[Index];
}在集合中,语法 Collection.Item(0) 和 Collection(0) 经常可以互换。如果希望集合支持该语法,则应使 Item 属性成为 Default 属性(在 Visual Basic 中)或实现索引器(在 C# 中)。有关详细信息,请参见组件的默认属性。
- 从“文件”菜单中选择“全部保存”。
现在您在类中实现了基本的集合功能。您实现了在集合中添加和移除小部件的方法,并实现了一个返回对适当项的 Widget 引用的属性。在下一节中将对 WidgetCollection 类进行测试。
测试项目
既然已经完成了 WidgetCollection 类,现在应该对其功能进行测试。若要执行此操作,则应创建一个简单 Windows 应用程序,该应用程序在集合中添加小部件、从集合中移除小部件并依次通过集合中的小部件。
创建测试项目
- 在解决方案资源管理器中,右击 Form1,然后单击快捷菜单上的“视图设计器”。
Form1 的设计器打开。
- 使用工具箱,向 Form1 中添加两个 Label 控件、两个 TextBox 控件和三个 Button 控件。
- 设置属性,如下所示:
| 控件 | 属性 | 值 |
|---|
| Label1 | Text | "Widget Name" |
| Label2 | Text | "Widget Index" |
| TextBox1 | Text | "" |
| TextBox2 | Text | "" |
| Button1 | Text | "Add a Widget" |
| Button2 | Text | "Remove a Widget" |
| Button3 | Text | "Review Widgets" |
在窗体的设计中,Label1 应标记 TextBox1,Label2 应标记 TextBox2。
- 在窗体设计器中,右击 WidgetTest 并选择“查看代码”。
WidgetTest 的代码编辑器打开。
- 在代码编辑器中,找到
Inherits 行 (Visual Basic) 或 class 行 (Visual C#)。紧接该行下方,键入下列代码: ' Visual Basic
' Creates a WidgetCollection object.
Dim myWidgetCollection as New WidgetCollection()
// C#
WidgetCollection myWidgetCollection = new WidgetCollection();
- 在设计器中,双击“button1”,它现在显示为“Add a Widget”。
- 在 button1_Click 事件处理程序中,添加代码以向集合中添加新的小部件,并将该小部件的名称设置为
textBox1 的值。 ' Visual Basic
If textbox1.Text = "" Then
MessageBox.Show("Please name your widget.")
Else
' Declares and instantiates a new widget.
Dim aWidget as New Widget()
' Sets the Name field of the new widget.
aWidget.Name = textBox1.Text
' Adds the new widget to the collection.
myWidgetCollection.Add(aWidget)
' Updates textBox2 with the index of the widget that was added.
' The index of a zero-based collection is Count property minus 1.
textBox2.Text = (myWidgetCollection.Count - 1).ToString()
End If
// C#
if (textBox1.Text == "")
MessageBox.Show("Please name your widget.");
else
{
// Declares and instantiates a new widget.
Widget aWidget = new Widget();
aWidget.Name = textBox1.Text;
// Adds the new widget to the collection
myWidgetCollection.Add(aWidget);
// Updates textbox2 with the index of the widget that was added.
// The index of a zero-based collection is Count property minus 1
textBox2.Text = (myWidgetCollection.Count -1).ToString();
} - 在 button2_Click 事件处理程序中,添加代码以移除在
textBox2 中指定的索引处的小部件。 ' Visual Basic
Try
myWidgetCollection.Remove(CInt(textBox2.Text))
Catch ex as System.InvalidCastException
MessageBox.Show("You have attempted to perform an invalid cast")
End Try
// C#
try
{
myWidgetCollection.Remove(int.Parse(textBox2.Text));
}
catch (System.InvalidCastException ex)
{
MessageBox.Show("You have attempted to perform an invalid cast");
}请注意,如果您必须提供错误处理以捕捉任何 System.InvalidCastException(可能是由于文本框中的字符无效而引发),则不必检查 textBox2 中是否存在索引的有效值,因为 WidgetCollection.Remove 方法会自动执行此检查。
- 在 button3_Click 事件处理程序中,编写代码以循环通过集合的所有成员,并在消息框中按顺序显示它们的名称。
' Visual Basic
Dim counter as Integer
For counter = 0 to myWidgetCollection.Count - 1
MessageBox.Show(myWidgetCollection.Item(counter).Name)
Next
// C#
int counter;
for(counter = 0; counter <= myWidgetCollection.Count - 1; counter++)
{
MessageBox.Show(myWidgetCollection.Item(counter).Name);
}也可以使用 For Each...Next 循环通过集合中的成员。
- 在解决方案管理器中,右击“WidgetProject”并选择“属性”。“WidgetProject 属性页”打开。在“启动对象”下,从菜单中选择 WidgetProject.Form1,并单击“确定”关闭该页。
您现在将运行测试应用程序。您将测试 Add 方法、Remove 方法以及在集合中对 Widget 对象的检索。
测试集合
- 在“Widget Name”文本框中,键入 Widget0 并单击“Add a Widget”按钮。重复该操作两次,分别用 Widget1 和 Widget2 代替 Widget0。
三个小部件现在已添加到集合中。
- 单击“Review Widgets”按钮。
每个小部件的名称依次出现在消息框中。
- 在“Widget Index”文本框中,键入 1 并单击“Remove a Widget”按钮。
索引 1 处的小部件被移除。索引动态更新,先前占用索引 2 位置的小部件现在占用索引 1。
- 单击“Review Widgets”按钮。
每个小部件的名称再次依次显示在消息框中。注意,不再显示“Widget1”,因为它已从集合中移除。
在此演练中,您学习了如何通过从 System.Collections.CollectionBase 类继承来实现基本的集合功能。您学习了如何使集合具有强类型以及如何实现 Add 和 Remove 方法以及 Item 属性。有关可用于创建集合类的基类的更多信息,请参见 System.Collections 命名空间。
请参见
System.Collections 命名空间 | 用集合管理对象 | 在类中使用集合