Tải bản đầy đủ - 0 (trang)
13-4. Implement an Enumerable Collection

13-4. Implement an Enumerable Collection

Tải bản đầy đủ - 0trang

CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



IEnumerable instances. Within the body of the member, use the yield return statement just

mentioned, and the C# compiler will generate the appropriate code automatically. To use one of the

alternative enumerations from a foreach statement, you must directly reference the appropriate

member, as in this example:

foreach (node n in Tree.BreadthFirst)



The Code

The following example demonstrates the creation of an enumerable collection using the IEnumerable

and IEnumerator interfaces in conjunction with the yield return and yield break statements. The

Team class, which represents a team of people, is a collection of enumerable TeamMember objects.

using System;

using System.Collections.Generic;

namespace Apress.VisualCSharpRecipes.Chapter13

{

// The TeamMember class represents an individual team member.

public class TeamMember

{

public string Name;

public string Title;

// Simple TeamMember constructor.

public TeamMember(string name, string title)

{

Name = name;

Title = title;

}

// Returns a string representation of the TeamMember.

public override string ToString()

{

return string.Format("{0} ({1})", Name, Title);

}

}

// Team class represents a collection of TeamMember objects.

public class Team

{

// A List to contain the TeamMember objects.

private List teamMembers = new List();



637



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



// Implement the GetEnumerator method, which will support

// iteration across the entire team member List.

public IEnumerator GetEnumerator()

{

foreach (TeamMember tm in teamMembers)

{

yield return tm;

}

}

// Implement the Reverse method, which will iterate through

// the team members in alphabetical order.

public IEnumerable Reverse

{

get

{

for (int c = teamMembers.Count - 1; c >= 0; c--)

{

yield return teamMembers[c];

}

}

}

// Implement the FirstTwo method, which will stop the iteration

// after only the first two team members.

public IEnumerable FirstTwo

{

get

{

int count = 0;

foreach (TeamMember tm in teamMembers)

{

if (count >= 2)

{

// Terminate the iterator.

yield break;

}

else

{

// Return the TeamMember and maintain the iterator.

count++;

yield return tm;

}

}

}

}



638



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



// Adds a TeamMember object to the Team.

public void AddMember(TeamMember member)

{

teamMembers.Add(member);

}

}

// A class to demonstrate the use of Team.

public class Recipe13_04

{

public static void Main()

{

// Create and populate a new Team.

Team team = new Team();

team.AddMember(new TeamMember("Curly", "Clown"));

team.AddMember(new TeamMember("Nick", "Knife Thrower"));

team.AddMember(new TeamMember("Nancy", "Strong Man"));

// Enumerate the entire Team using the default iterator.

Console.Clear();

Console.WriteLine("Enumerate using default iterator:");

foreach (TeamMember member in team)

{

Console.WriteLine(" " + member.ToString());

}

// Enumerate the first two Team members only.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Enumerate using the FirstTwo iterator:");

foreach (TeamMember member in team.FirstTwo)

{

Console.WriteLine(" " + member.ToString());

}

// Enumerate the entire Team in reverse order.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Enumerate using the Reverse iterator:");

foreach (TeamMember member in team.Reverse)

{

Console.WriteLine(" " + member.ToString());

}

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter");

Console.ReadLine();

}

}

}



639



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



13-5. Implement an Enumerable Type Using a Custom

Iterator

Problem

You need to create an enumerable type but do not want to rely on the built-in iterator support provided

by the .NET Framework (described in recipe 13-4).



Solution

Implement the interface System.Collections.IEnumerable on your collection type. The GetEnumerator

method of the IEnumerable interface returns an enumerator, which is an object that implements the

interface System.Collections.IEnumerator. The IEnumerator interface defines the methods used by the

foreach statement to enumerate the collection.

Implement a private inner class within the enumerable type that implements the interface

IEnumerator and can iterate over the enumerable type while maintaining appropriate state information.

In the GetEnumerator method of the enumerable type, create and return an instance of the iterator class.



How It Works

The automatic iterator support built into C# is very powerful and will be sufficient in the majority of

cases. However, in some cases you may want to take direct control of the implementation of your

collection’s iterators. For example, you may want an iterator that supports changes to the underlying

collection during enumeration.

Whatever your reason, the basic model of an enumerable collection is the same as that described in

recipe 13-4. Your enumerable type should implement the IEnumerable interface, which requires you to

implement a method named GetEnumerator. However, instead of using the yield return statement in

GetEnumerator, you must instantiate and return an object that implements the IEnumerator interface.

The IEnumerator interface provides a read-only, forward-only cursor for accessing the members of the

underlying collection. Table 13-2 describes the members of the IEnumerator interface. The IEnumerator

instance returned by GetEnumerator is your custom iterator—the object that actually supports

enumeration of the collection’s data elements.



640



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



Table 13-2. Members of the IEnumerator Interface



Member



Description



Current



Property that returns the current data element. When the enumerator is created, Current

refers to a position preceding the first data element. This means you must call MoveNext

before using Current. If Current is called and the enumerator is positioned before the first

element or after the last element in the data collection, Current must throw a

System.InvalidOperationException.



MoveNext



Method that moves the enumerator to the next data element in the collection. Returns true if

there are more elements; otherwise, it returns false. If the underlying source of data changes

during the life of the enumerator, MoveNext must throw an InvalidOperationException.



Reset



Method that moves the enumerator to a position preceding the first element in the data

collection. If the underlying source of data changes during the life of the enumerator, Reset

must throw an InvalidOperationException.



If your collection class contains different types of data that you want to enumerate separately,

implementing the IEnumerable interface on the collection class is insufficient. In this case, you would

implement a number of properties that return different IEnumerator instances.



The Code

The TeamMember, Team, and TeamMemberEnumerator classes in the following example demonstrate the

implementation of a custom iterator using the IEnumerable and IEnumerator interfaces. The TeamMember

class represents a member of a team. The Team class, which represents a team of people, is a collection of

TeamMember objects. Team implements the IEnumerable interface and declares a separate class, named

TeamMemberEnumerator, to provide enumeration functionality. Team implements the Observer pattern

using delegate and event members to notify all TeamMemberEnumerator objects if their underlying Team

changes. (See recipe 13-11 for a detailed description of the Observer pattern.) The TeamMemberEnumerator

class is a private nested class, so you cannot create instances of it other than through the

Team.GetEnumerator method.

using System;

using System.Collections;

namespace Apress.VisualCSharpRecipes.Chapter13

{

// TeamMember class represents an individual team member.

public class TeamMember

{

public string Name;

public string Title;



641



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

13-4. Implement an Enumerable Collection

Tải bản đầy đủ ngay(0 tr)

×