http://www.developer.com/net/cplus/article.php/3398191/Managed-Extensions-Adding-Enumeration-to-Your-Classes.htm
Welcome to this week's installment of .NET Tips & Techniques! Each week, award-winning Architect and Lead Programmer Tom Archer demonstrates how to perform a practical .NET programming task using either C# or Managed C++ Extensions.
In addition to providing thousands of classes and types that enable us to create richer and more robust class hierarchies, the .NET BCL (Base Class Library) also defines many interfaces that enable the class writer to incorporate powerful features simply by implementing a given interface and its members. This concept, called interface-based programming, creates a contract between the implementing class and its clients, such that the client can be assured of what to expect from the class. The BCL even provides special operators and methods, such that client code can verify that a given interface is implemented before attempting to use it.
As an example, say that you define a class that implements an interface called ISomeInterface. Using Visual C++ and Managed Extensions, the client could then use the __typeof operator and Type::GetInterface method to verify that the ISomeInterface interface is implemented:
In order to provide enumeration for a collection of Article objects, you could perform the following steps:
Please note that in order to make the following steps more clear in terms of where to insert code, I've duplicated code in some cases. For that reason, any step that includes previously shown code will display the new code to be inserted in bold.
Therefore, the enumerator class contains an internal parent collection object as well as a position member to keep track of where the client is when enumerating the collection. Here's how you would define and initialize these:
Managed Extensions: Adding Enumeration to Your Classes
August 23, 2004
Type* t = __typeof(myVar);
if (t->GetInterface(S"ISomeInterface"))
{
...
If the client is a C# application, this same verification would look like the following—where the C# is operator is used:
if (myVar is IEnumerable)
{
...
Having said that, one set of interfaces that you'll find quite useful is the IEnumerable and IEnumerator interfaces. These interfaces enable you to quickly and easily define your classes, such that client code can enumerate them in a type-safe and object-specific manner. This article presents step-by-step instructions for performing this task.
Implementing the IEnumerable and IEnumerator Interfaces
As a demo project, say you have a class called Article that contains some basic fields, such as title, author, and category:
__gc class Article
{
public:
Article(String* title, String* author, String* category)
{
this->title = title;
this->author = author;
this->category = category;
}
protected:
String* title;
String* author;
String* category;
public:
__property String* get_Title() { return this->title; }
__property String* get_Author() { return this->author; }
__property String* get_Category() { return this->category; }
};
__gc class Article
{
...
};
__gc class ArticleCollection : public IEnumerable
{
};
__gc class ArticleCollection : public IEnumerable
{
protected:
ArrayList* articles;
__gc class ArticleCollection : public IEnumerable
{
...
public:
IEnumerator* GetEnumerator()
{
return dynamic_cast<IEnumerator*>(
new ArticleEnumerator(this));
}
public:
__gc class ArticleEnumerator : public IEnumerator
{
};
...
__gc class ArticleEnumerator : public IEnumerator
{
protected:
ArticleCollection* collection;
int position;
public:
ArticleEnumerator(ArticleCollection* collection)
{
this->collection = collection;
position = -1;
}
...
__gc class ArticleEnumerator : public IEnumerator
{
...
public:
bool MoveNext()
{
position++;
return (position < collection->articles->Count);
}
__property Object* get_Current()
{
if (0 > position
|| position >= collection->articles->Count)
throw new InvalidOperationException();
return collection->articles->Item[position];
}
void Reset()
{
position = -1;
}
...
The Client Side
Now that the Article class is enumerable, look at how client code enumerates a collection of Article objects. Assuming you instantiated and filled an object of type ArticleCollection, you could code a C++ client as follows:
Type* t = __typeof(ArticleCollection);
if (t->GetInterface(S"IEnumerable"))
{
// m_articles is a class-level object of type ArticleCollection
IEnumerator* en = m_articles->GetEnumerator();
while (en->MoveNext())
{
Article* article = dynamic_cast
In C#, the client would look like the following:
if (m_articles is IEnumerable)
{
foreach(Article article in m_articles)
{
...
}
}
As you can see, C# supports a couple of keywords that reduce the typing a bit, but they both work basically the same.
C# Clients and the foreach Operator
While this article specifically covers how to provide enumeration for your classes using Managed Extensions, you should always take care to accommodate the idiosyncrasies of other .NET languagesmdash;especially the more popular languages. To that extent, C# programmers expect to be able to use the foreach operator in enumerating collections. This operator can be used only on expressions that are collection types. As defined in the .NET documentation, a collection type is one that either implements the IEnumerable interface (as you've done here) or implements the collection pattern, which is defined as follows:
Looking Ahead
In the next few articles, I'll continue this theme on enumerable collections by covering topics such as adding sorting capabilities to your collections, versioning your enumerators, and fine-tuning your enumerators for better performance.