|
![]() |
Built-In Interfaces: IList |
Interfaces and Collections |
Starting a Collection |
A collection is a group of items. All the items in the (same) group must be of the same type. To give you the foundation for (or to create) a collection, the .NET Framework provides an interface named ICollection. Actually, that interface doesn't provide much functionality. Its primary role is to let you know the number of items in a collection. To do this, the interface is equipped with a (read-only) property named Count:
abstract Count : int with get
While a collection is being created or for a collection that exists already, this property holds the number of items in the collection. The only operation the ICollection interface provides is the ability to copy the items from its collection to another type of collection (called an array).
Iterating Through a Collection |
Once a collection exists, the most routine operation is to access each one of its items or members, for any reason. To support this operation, the .NET Framework provides an interface named IEnumerator:
type IEnumerator = interface end
The IEnumerator interface allows you to visit an item, do anything on it, and move to the next item in the collection. It does this through a property (named Current) and two methods (named MoveNext and Reset). Normally, you will not need to use that property or to call those methods. As we will see in this lesson, the operations are performed behind the scenes for you. You may be concerned with the IEnumerator interface only if you are creating your own collection class. Fortunately, both the .NET Framework and the F# language provide all the collection classes we need for our lessons.
Enumerating a Collection |
In order to iterate through a collection, you use an object that holds a reference to the iterator. The main role of such an object is to indicate whether iteration is possible or available on the collection. To let you get such a reference, the .NET Framework provides an interface named IEnumerable:
type IEnumerable = interface end
The IEnumerable interface is equipped with only one method, named GetEnumerator. Its signature is:
abstract GetEnumerator : unit -> IEnumerator
As you may imagine, the role of the IEnumerable interface is to check whether iteration is available in a certain collection and, if so, to provide an object that can perform iteration.
Introduction to Lists and Collections |
In the .NET Framework, the primary interface used to create a collection is called IList. It implements both the ICollection and the IEnumerable interfaces:
type IList = interface interface ICollection interface IEnumerable end
The IList interface provides its implementers with all the primary properties and routine methods necessary for a collection class. In many cases, you will not need to create your own collection classes (although you can). Both the F# language and especially the .NET framework provide collection classes for most scenarios you can think of. As a matter of fact, there are many collection-based controls that already support collections using appropriate properties. The classes of most of those controls are equipped with a property named Items. That's the case for the list box. The Items property for the ListBox is based on a custom class named ObjectCollection. It implements the IList, the ICollection, and the IEnumerable interface:
type ObjectCollection = class interface IList interface ICollection interface IEnumerable end
As mentioned already, the IList interface is equipped to perform all necessary operations of a collection:
abstract Add : value:Object -> intThis method takes one argument as the item to be added. Once an item has been added, it occupies a specific position, also called an index. The first item to be added occupies index 0. The second item is at index 1, and so on. When you call the Add() method, if it succeeds in adding the item, the new item is positioned at the next index and the method returns that index. You can use that index for any reason you judge necessary. Here are examples:
open System open System.Windows.Forms // Form: Car Dealer let dealer = new Form(Width = 220, Height = 160, Text = "Car Manufacturers") // Label: Manufacturers dealer.Controls.Add(new Label(Left = 18, Top = 20, Width = 84, Text = "Manufacturers:")) // List Box: Manufacturers let lbxManufacturers = new ListBox(Left = 108, Top = 20, Width = 88) dealer.Controls.Add lbxManufacturers let mutable index : int = 0 index <- lbxManufacturers.Items.Add "Lincoln" index <- lbxManufacturers.Items.Add "Toyota" index <- lbxManufacturers.Items.Add "Volkswagon" index <- lbxManufacturers.Items.Add "Fiat" index <- lbxManufacturers.Items.Add "Jaguar" do Application.Run dealerThis would produce:
open System
open System.Windows.Forms
// Form: Car Dealer
let dealer = new Form(Width = 220, Height = 160, Text = "Car Manufacturers")
// Label: Manufacturers
dealer.Controls.Add(new Label(Left = 18, Top = 20, Width = 84, Text = "Manufacturers:"))
// List Box: Manufacturers
let lbxManufacturers = new ListBox(Left = 108, Top = 20, Width = 88, Height = 80)
dealer.Controls.Add lbxManufacturers
// Label: Count
let lblCount = new Label(Left = 18, Top = 100, Width = 200, Text = "Count:")
dealer.Controls.Add(lblCount)
let mutable index : int = 0
index <- lbxManufacturers.Items.Add "Lincoln"
index <- lbxManufacturers.Items.Add "Toyota"
index <- lbxManufacturers.Items.Add "Volkswagon"
index <- lbxManufacturers.Items.Add "Fiat"
index <- lbxManufacturers.Items.Add "Jaguar"
lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items."
do Application.Run dealer
This would produce:
abstract Insert : index : int * value : Object -> unitThis method takes two arguments. The value item is the object to be inserted in the collection. The index argument specifies the position that the new item should occupy. The index value should be the actual position - 1. Here is an example:
open System
open System.Windows.Forms
// Form: Car Dealer
let dealer = new Form(Width = 220, Height = 160, Text = "Car Manufacturers")
// Label: Manufacturers
dealer.Controls.Add(new Label(Left = 18, Top = 20, Width = 84, Text = "Manufacturers:"))
// List Box: Manufacturers
let lbxManufacturers = new ListBox(Left = 108, Top = 20, Width = 88, Height = 90)
dealer.Controls.Add lbxManufacturers
// Label: Count
let lblCount = new Label(Left = 18, Top = 110, Width = 200, Text = "Count:")
dealer.Controls.Add(lblCount)
let mutable index : int = 0
index <- lbxManufacturers.Items.Add "Lincoln"
index <- lbxManufacturers.Items.Add "Toyota"
index <- lbxManufacturers.Items.Add "Volkswagon"
index <- lbxManufacturers.Items.Add "Fiat"
index <- lbxManufacturers.Items.Add "Jaguar"
lbxManufacturers.Items.Insert(2, "Ford")
lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items."
do Application.Run dealer
This would produce:
abstract Item : index:int -> Object with get, setThe get part allows you to get an item based on its position. This is done by passing the necessary numeric index to the square brackets of the Item property. Here is an example:
open System open System.Windows.Forms // Form: Car Dealer let dealer = new Form(Width = 220, Height = 195, Text = "Car Manufacturers") // Label: Manufacturers dealer.Controls.Add(new Label(Left = 18, Top = 20, Width = 84, Text = "Manufacturers:")) // List Box: Manufacturers let lbxManufacturers = new ListBox(Left = 108, Top = 20, Width = 88, Height = 90) dealer.Controls.Add lbxManufacturers // Label: Count let lblCount = new Label(Left = 18, Top = 110, Width = 200, Text = "Count:") dealer.Controls.Add(lblCount) // Label: Indexed Item let lblIndexedItem = new Label(Left = 18, Top = 132, Width = 188, Text = "IndexedItem:") dealer.Controls.Add(lblIndexedItem) let mutable index : int = 0 index <- lbxManufacturers.Items.Add "Lincoln" index <- lbxManufacturers.Items.Add "Toyota" index <- lbxManufacturers.Items.Add "Volkswagon" index <- lbxManufacturers.Items.Add "Fiat" index <- lbxManufacturers.Items.Add "Jaguar" lbxManufacturers.Items.Insert(2, "Ford") lblIndexedItem.Text <- "Item at Index 3 = " + string (lbxManufacturers.Items.Item(3)) lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items." do Application.Run dealerThis would produce:
open System open System.Windows.Forms // Form: Car Dealer let dealer = new Form(Width = 220, Height = 168, Text = "Car Manufacturers") // Label: Manufacturers dealer.Controls.Add(new Label(Left = 18, Top = 20, Width = 84, Text = "Manufacturers:")) // List Box: Manufacturers let lbxManufacturers = new ListBox(Left = 108, Top = 20, Width = 88, Height = 90) dealer.Controls.Add lbxManufacturers // Label: Count let lblCount = new Label(Left = 18, Top = 110, Width = 200, Text = "Count:") dealer.Controls.Add(lblCount) let mutable index : int = 0 index <- lbxManufacturers.Items.Add "Lincoln" index <- lbxManufacturers.Items.Add "Toyota" index <- lbxManufacturers.Items.Add "Volkswagon" index <- lbxManufacturers.Items.Add "Fiat" index <- lbxManufacturers.Items.Add "Jaguar" lbxManufacturers.Items.Insert(2, "Ford") lbxManufacturers.Items.[3] <- "Buick" lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items." do Application.Run dealerThis would produce:
abstract Contains : value:Object -> boolThis method takes as argument the item to look for in the collection. If the item exists, the method returns true. If there is no such an item in the collection, the method returns false. Here are examples of calling this method:
open System open System.Windows.Forms // Form: Car Dealer let dealer = new Form(Width = 240, Height = 215, Text = "Car Manufacturers") // Label: Manufacturers dealer.Controls.Add(new Label(Left = 12, Top = 20, Width = 84, Text = "Manufacturers:")) // List Box: Manufacturers let lbxManufacturers = new ListBox(Left = 98, Top = 20, Width = 120, Height = 90) dealer.Controls.Add lbxManufacturers // Label: Count let lblCount = new Label(Left = 12, Top = 110, Width = 200, Text = "Count:") dealer.Controls.Add(lblCount) // Label: Containment let lblContainment = new Label(Left = 12, Top = 132, Width = 258, Text = "Containment") dealer.Controls.Add(lblContainment) // Label: Search let lblSearch = new Label(Left = 12, Top = 158, Width = 258, Text = "Search") dealer.Controls.Add(lblSearch) let mutable index : int = 0 index <- lbxManufacturers.Items.Add "Lincoln" index <- lbxManufacturers.Items.Add "Toyota" index <- lbxManufacturers.Items.Add "Volkswagon" index <- lbxManufacturers.Items.Add "Fiat" index <- lbxManufacturers.Items.Add "Jaguar" lbxManufacturers.Items.Insert(2, "Ford") lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items." if lbxManufacturers.Items.Contains("Volvo") then lblContainment.Text <- "The collection contains Volvo." else lblContainment.Text <- "The collection DOES NOT contain Volvo." if lbxManufacturers.Items.Contains("Toyota") then lblSearch.Text <- "The collection contains Toyota." else lblSearch.Text <- "The collection DOES NOT contain Toyota." do Application.Run dealerThis would produce:
abstract Remove : value:Object -> unitThe item to be removed is passed to the method. This means that you must know or build the item before passing it. As an alternative, you can delete an item based on its position in the collection. To support this operation, the IList interface provides the RemoveAt() method. Its signature is:
abstract RemoveAt : index:int -> unitWhen calling this function, if you provide an index that the compiler cannot find, it would produce an error. To let you delete all items in one step, the IList interface is equipped with a method named Clear. Its signature is:
abstract Clear : unit -> unitHere is an example of calling this method:
open System open System.Windows.Forms // Form: Car Dealer let dealer = new Form(Width = 240, Height = 168, Text = "Car Manufacturers") // Label: Manufacturers dealer.Controls.Add(new Label(Left = 12, Top = 20, Width = 84, Text = "Manufacturers:")) // List Box: Manufacturers let lbxManufacturers = new ListBox(Left = 98, Top = 20, Width = 120, Height = 90) dealer.Controls.Add lbxManufacturers // Label: Count let lblCount = new Label(Left = 12, Top = 110, Width = 200, Text = "Count:") dealer.Controls.Add(lblCount) lbxManufacturers.Items.Add "Lincoln" |> ignore lbxManufacturers.Items.Add "Toyota" |> ignore lbxManufacturers.Items.Add "Volkswagon" |> ignore lbxManufacturers.Items.Add "Fiat" |> ignore lbxManufacturers.Items.Add "Jaguar" |> ignore lbxManufacturers.Items.Insert(2, "Ford") lbxManufacturers.Items.Clear() lblCount.Text <- "The collection contains " + lbxManufacturers.Items.Count.ToString() + " items." do Application.Run dealer