Книга: C# 2008 Programmer

System.Collections.ObjectModel

System.Collections.ObjectModel

The System.Collections.ObjectModel namespace in the .NET class library contains several generic classes that deal with collections. These classes are described in the following table.

Generic Class Description
Collection<T> Provides the base class for a generic collection.
KeyedCollection<TKey, TItem> Provides the abstract base class for a collection whose keys are embedded in the values.
ObservableCollection<T> Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
ReadOnlyCollection<T> Provides the base class for a generic read-only collection.
ReadOnlyObservableCollection<T> Represents a read-only ObservableCollection<T>.

Let's take a look at Collection<T>, one of the classes available. It is similar to the generic List<T> class. Both Collection<T> and List<T> implement the IList<T> and ICollection<T> interfaces. The main difference between the two is that Collection<T> contains virtual methods that can be overridden, whereas List<T> does not have any.

The List<T> generic class is discussed in details in Chapter 13.

The following code example shows how to use the generic Collection<T> class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace CollectionEg1 {
 class Program {
  static void Main(string[] args) {
   Collection<string> names = new Collection<string>();
   names.Add("Johnny");
   names.Add("Michael");
   names.Add("Wellington");
   foreach (string name in names) {
    Console.WriteLine(name);
   }
   Console.ReadLine();
  }
 }
}

Here's the example's output:

Johnny
Michael
Wellington

To understand the usefulness of the generic Collection<T> class, consider the following example where you need to write a class to contain the names of all the branches a company has:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace CollectionEg2 {
 class Program {
  static void Main(string[] args) {}
 }
 public class Branch {
  private List<string> _branchNames = new List<string>();
  public List<string> BranchNames {
   get {
    return _branchNames;
   }
  }
 }
}

In this example, the Branch class exposes a public read-only property called BranchNames of type List<T>. To add branch names to a Branch object, you first create an instance of the Branch class and then add individual branch names to the BranchNames property by using the Add() method of the List<T> class:

static void Main(string[] args) {
 Branch b = new Branch();
 b.BranchNames.Add("ABC");
 b.BranchNames.Add("XYZ");
}

Suppose now that your customers request an event for the Branch class so that every time a branch name is deleted, the event fires so that the client of Branch class can be notified. The problem with the generic List<T> class is that there is no way you can be informed when an item is removed.

A better way to resolve this issue is to expose BranchName as a property of type Collection<T> instead of List<T>. That's because the generic Collection<T> type provides four overridable methods — ClearItems(), InsertItem(), RemoveItem(), and SetItem() — which allow a derived class to be notified when a collection has been modified.

Here's how rewriting the Branch class, using the generic Collection<T> type, looks:

public class Branch {
 public Branch() {
  _branchNames = new BranchNamesCollection(this);
 }
 private BranchNamesCollection _branchNames;
 public Collection<string> BranchNames {
  get {
   return _branchNames;
  }
 }
 //---event raised when an item is removed---
 public event EventHandler ItemRemoved;
 //---called from within the BranchNamesCollection class---
 protected virtual void RaiseItemRemovedEvent(EventArgs e) {
  if (ItemRemoved != null) {
   ItemRemoved(this, e);
  }
 }
 private class BranchNamesCollection : Collection<string> {
  private Branch _b;
  public BranchNamesCollection(Branch b) _b = b;
  //---fired when an item is removed---
  protected override void RemoveItem(int index) {
   base.RemoveItem(index);
   _b.RaiseItemRemovedEvent(EventArgs.Empty);
  }
 }
}

There is now a class named BranchNamesCollection within the Branch class. The BranchNamesCollection class is of type Collection<string>. It overrides the RemoveItem() method present in the Collection<T> class. When an item is deleted from the collection, it proceeds to remove the item by calling the base RemoveItem() method and then invoking a function defined in the Branch class: RaiseItemRemovedEvent(). The RaiseItemRemovedEvent() function then raises the ItemRemoved event to notify the client that an item has been removed.

To service the ItemRemoved event in the Branch class, modify the code as follows:

static void Main(string[] args) {
 Branch b = new Branch();
 b.ItemRemoved += new EventHandler(b_ItemRemoved);
 b.BranchNames.Add("ABC");
 b.BranchNames.Add("XYZ");
 b.BranchNames.Remove("XYZ");
 foreach (string branchName in b.BranchNames) {
  Console.WriteLine(branchName);
 }
 Console.ReadLine();
}
static void b_ItemRemoved(object sender, EventArgs e) {
 Console.WriteLine("Item removed!");
}

And here's the code's output:

Item removed!

As a rule of thumb, use the generic Collection<T> class (because it is more extensible) as a return type from a public method, and use the generic List<T> class for internal implementation.

Оглавление книги


Генерация: 1.449. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз