Click here to Skip to main content
Click here to Skip to main content

Implementing custom collection classes with MC++

By , 12 Jun 2002
 

Introduction

A collection class is basically a pool of indexed objects. This means we know how many objects the collection has at any one time. We can enumerate the objects one by one. We can access the object associated with a particular index. Usually collection classes are also sortable. For collection classes to be sortable, the objects it holds or collects must be comparable among objects of it's same type. In this tutorial we'll see how to design and create collection classes of our own. We'll create a class called Student which implements the IComparable interface. This will serve as the object we collect. We'll also have a nested class inside the Student class called StudentAgeComparer which implements the IComparer interface. This class is for sorting purposes. Then we'll create the class called StudentCollection which is the collection class for the Student class and which implements the IEnumerable interface. The StudentCollection class will hold a nested class called StudentEnumerator which implements the IEnumerator interface. This is the interface that implements all the required methods and properties that makes a class enumerable. By the way C# programmers might be interested to know that they can use foreach to enumerate collection classes that implement IEnumerable and IEnumerator interfaces.

The IEnumerable interface

IEnumerable is an interface that a collection class implements if it's members are to be enumerated. The foreach C# keyword can enumerate only those classes that implement IEnumerable. It's sole purpose is to expose the enumerator object which is used to enumerate the various objects in the collection in a sequential order. This enumerator object is nothing but a pointer to an instance of a class that implements the IEnumerator interface. Typically when we have a class that implements the IEnumerable interface we have an inner class that acts as the enumerator class of this class. The inner enumerator class will implement IEnumerator.

The IEnumerable interface defines just one single method called GetEnumerator which simply returns the enumerator for the class. A typical scenario is shown below where we have a collection class called AbcCollection which implements IEnumerable and a nested inner class called AbcCollectionEnumerator which implements IEnumerator. The advantage of making the IEnumerator implementing class a nested inner class of the IEnumerable implementing class is that the enumerator will have access to the private fields and methods of the collection class.

__gc class AbcCollection : public IEnumerable 
{
public:
    IEnumerator* GetEnumerator()
    {
        ...
    }

    __gc class AbcCollectionEnumerator : public IEnumerator
    {
        ...
    };
};

The IEnumerator interface

Any collection class that allows it's collected items to be enumerated must implement an enumerator which implements the IEnumerator interface. The enumerator is initially positioned just before the first item. There is a method called MoveNext which advances the enumerator to the next object in the collection. If the position of the enumerator was successfully advanced MoveNext returns true. If MoveNext failed because the enumerator has reached the end of the collection, then it returns false. If the collection has been modified after the enumerator was instantiated then MoveNext will throw an InvalidOperationException exception.

The IEnumerator interface has a property called Current which returns the current object in the collection that the enumerator is pointing to. If the enumerator is positioned before the first element in the collection or if the enumerator has enumerated past the collection's edge, then an InvalidOperationException exception is thrown. An InvalidOperationException exception is also thrown if the collection has been modified after the enumerator has been instantiated. The third and last member IEnumerator implements is the Reset method which will reset the enumerator to it's initial position of one before the first object in the collection. Typically a class that implements the IEnumerator interface has a constructor that takes an argument. This argument will be of the type of the collection class, that this class enumerates. There will also be a private member of the collection class type and the constructor will initialize it with the argument passed to it.

__gc class AbcCollectionEnumerator : public IEnumerator
{
    AbcCollectionEnumerator(AbcCollection* abc)
    {
        m_privmember = abc;
        ...
    }
    ...
};

The IComparable interface

Any class that needs to be ordered or sorted will need to implement IComparable. That is not strictly true in the sense that another class can be used as a comparer for objects of our class and this comparer class will need to implement the IComparer interface. But we'll touch that later. Anyway IComparable defines only one member which is a method called CompareTo. CompareTo will take an object of the same type as the class that implements IComparable and will return an int. The returned int will be 0 if the object is equal to the current instance, a negative number if the current instance is less than the object and a positive non-zero number if the current instance is greater than the object. An array or array list of objects that implement IComparable are sortable.

The IComparer interface

The IComparer interface provides a method to compare two objects and is used for sorting collection classes. One of the overrides of the Sort() functions take an IComparer object as argument and will use this IComparer to compare the objects that are to be sorted. The IComparer interface defines only one method called Compare. Similar to the CompareTo method of the IComparable interface, this returns 0 if both objects are equal. It will return a negative number if the first object is less than the second object and a non-zero positive number if the first object is greater than the second object. Typical implementations are done using the CompareTo method of one or more of the members of the objects to be compared.

Student class

The Student class that we are going to implement will implement IComparable so that Student objects may be compared and sorted. In addition we'll also have an inner nested class called StudentAgeComparer which provides an alternate sorting based on an alternate criteria from the default one. The Student class is listed below in an incomplete manner to save space. To see the complete listing you can take a look at the source code provided with the article or the full code listing provided at the end of the article.

__gc class Student : public IComparable
{
public:
    Student(String* sname, String* srollnum, int sage)
    {
        ...
    }

    void Display()
    {
        ...
    }

    int CompareTo(Object* obj)
    {
        Student* tmp = dynamic_cast<Student*>(obj);
        return m_name->CompareTo(tmp->m_name);
    }

    __gc class StudentAgeComparer : public IComparer 
    {
        ...
    };

private:
    String* m_name;
    String* m_rollnum;
    int     m_age;
};

As you can see, we don't do anything fancy in the CompareTo method. We simply delegate the comparison to a lower level by calling CompareTo on the m_name member of the object which is a String. The String class implements IComparable and thus we are saved some coding, which is excellent. Thus by default a Student object collection will be sorted on the basis of the Student object's m_name member. Now assume that someone says that they want to sort a Student object collection or array by age. To facilitate for such a contingency we have an inner class called StudentAgeComparer which implements the IComparer interface. We'll see it's implementation below.

__gc class StudentAgeComparer : public IComparer 
{
public:
    int Compare(Object* x,Object* y)
    {
        Student* x1 = dynamic_cast<Student*>(x);
        Student* y1 = dynamic_cast<Student*>(y);
        return x1->m_age.ToString()->CompareTo(y1->m_age.ToString());
    }
};

Again we delegate the comparison to a lower level. This time we call the CompareTo function on the String returned by calling ToString() on the m_age member. We could have called it directly on the int but then we'd have had to do boxing on our own, this is MC++ remember, not C#. I thought it best to use the String forms to do the comparison. Later on when we implement the collection, we'll see how we implement an alternate sort that uses the StudentAgeComparer to do sorting based on a student's age instead of on a student's name which is the default.

StudentCollection class

The StudentCollection class is a collection class of Student objects and implements IEnumerable. It also has an inner class called StudentEnumerator which acts as the enumerator for the StudentCollection class. The StudentCollection class has a private ArrayList member which is used to store the various Student objects. I chose an ArrayList instead of an Array because an ArrayList is dynamically resizable. Thus I don't need to specify a default size. The ArrayList will keep growing as I keep adding more objects. The StudentCollection is listed below and as before the listing is only partial. Look at the zipped source code or the full listing at the end of the article for the complete listing of code.

__gc class StudentCollection : public IEnumerable
{
public:
    StudentCollection()
    {
        m_students = new ArrayList();
        m_dirty = false;
    }


    __gc class StudentEnumerator : public IEnumerator
    {
        ...
    };


    IEnumerator* GetEnumerator()
    {
        m_dirty = false;
        return dynamic_cast<IEnumerator*>(new StudentEnumerator(this));
    }

    int Add(Object* value)
    {
        m_dirty = true;
        return m_students->Add(value);
    }

    void Sort()
    {
        m_dirty=true;
        m_students->Sort();
    }

    void SortByAge()
    {
        m_dirty=true;
        m_students->Sort(new Student::StudentAgeComparer());
    }

private:
    ArrayList* m_students;
    bool m_dirty;
};

The GetEnumerator() method returns a new instance of the StudentEnumerator class. Thus each time we call GetEnumerator() a new enumerator is created. If any change is made to the collection we set a dirty flag to true to indicate to the enumerator that the collection has been changed after the enumerator has been created. There are two Sort methods provided. The first Sort method simply calls the zero-argument Sort overloaded method of the ArrayList class. In this case comparison and sorting can be done on the Student object because it implements IComparable. There is also an alternate sorting method called SortByAge where we call another overload of ArrayList's Sort() method where we pass it an instance of an object that implements the IComparer interface. In this case we pass a new instance of the StudentAgeComparer class. Now the relevance of the IComparable and the IComparer interfaces must have become clearer to you. Now let's take a look at the StudentEnumerator class.

__gc class StudentEnumerator : public IEnumerator
{
public:
    StudentEnumerator(StudentCollection* sc)
    {
        m_sc = sc;
        index = -1;
    }

    Object* get_Current()
    {
        if(index < 0 || index >= m_sc->m_students->Count || m_sc->m_dirty)
            throw new InvalidOperationException();

        return m_sc->m_students->Item[index];
    }

    void Reset()
    {
        m_sc->m_dirty = false;
        index = -1;
    }

    bool MoveNext()
    {
        if(m_sc->m_dirty)
            throw new InvalidOperationException();

        index++;

        return (index < m_sc->m_students->Count);
    } 

private:
    int index;
    StudentCollection* m_sc;
};

The enumerator class has a private member of type StudentCollection and in the constructor we assign the passed StudentCollection object to this private member. We also have an index which is by default set to -1 since the ArrayList index starts from 0. When a call is made to the Reset method we simply set the index back to -1 and set the dirty flag to false. In the MoveNext() method we throw an InvalidOperationException exception if the dirty flag is set. Else we increment index and if we haven't gone past the end of the collection, we return true, otherwise we return false. Similarly in the get implementation of the Current property, we check to see if the index is below 0 or if it has crossed the edge of the collection's limit. In either case or if the dirty flag has been set an exception of type InvalidOperationException is thrown. Otherwise the Student object in the ArrayList that has the current index is returned.

Enumerating our collection

StudentCollection* sc = new StudentCollection();

//Populate the collection

IEnumerator* iEnum = sc->GetEnumerator();

while(i->MoveNext())
{
    Student* stmp = dynamic_cast<Student*>(iEnum->Current);
    stmp->Display();
}

Screenshot of sample

Full source listing

#include "stdafx.h"

#using <mscorlib.dll>
#include <tchar.h>

using namespace System;
using namespace System::Collections;

__gc class Student : public IComparable
{
public:
    Student(String* sname, String* srollnum, int sage)
    {
        m_name = sname;
        m_rollnum = srollnum;
        m_age=sage;
    }

    void Display()
    {
        Console::WriteLine("{0}{1}{2}",
            m_name->PadRight(30),
            m_rollnum->PadRight(15),m_age.ToString());
    }

    int CompareTo(Object* obj)
    {
        Student* tmp = dynamic_cast<Student*>(obj);
        return m_name->CompareTo(tmp->m_name);
    }

    __gc class StudentAgeComparer : public IComparer 
    {
    public:
        int Compare(Object* x,Object* y)
        {
            Student* x1 = dynamic_cast<Student*>(x);
            Student* y1 = dynamic_cast<Student*>(y);
            return x1->m_age.ToString()->CompareTo(
                        y1->m_age.ToString());
        }
    };

private:
    String* m_name;
    String* m_rollnum;
    int m_age;
};

__gc class StudentCollection : public IEnumerable
{
public:
    StudentCollection()
    {
        m_students = new ArrayList();
        m_dirty = false;
    }


    __gc class StudentEnumerator : public IEnumerator
    {
    public:
        StudentEnumerator(StudentCollection* sc)
        {
            m_sc=sc;
            index = -1;
        }

        Object* get_Current()
        {
            if(index <0 || index >= m_sc->m_students->Count ||
                m_sc->m_dirty)
                throw new InvalidOperationException();
            return m_sc->m_students->Item[index];
        }

        void Reset()
        {
            m_sc->m_dirty = false;
            index=-1;
        }

        bool MoveNext()
        {
            if(m_sc->m_dirty)
                throw new InvalidOperationException();
            index++;

            return (index < m_sc->m_students->Count);
        }

    private:
        int index;
        StudentCollection* m_sc;
    };


    IEnumerator* GetEnumerator()
    {
        m_dirty = false;
        return dynamic_cast<IEnumerator*>(
                    new StudentEnumerator(this));
    }

    int Add(Object* value)
    {
        m_dirty = true;
        return m_students->Add(value);
    }

    void Sort()
    {
        m_dirty=true;
        m_students->Sort();
    }

    void SortByAge()
    {
        m_dirty=true;
        m_students->Sort(new Student::StudentAgeComparer());
    }

private:
    ArrayList* m_students;
    bool m_dirty;
};


int _tmain(void)
{ 
    Student *s1 = new Student("Sally Smith","GF/45/112",22);
    Student *s2 = new Student("Alice Brown","GF/45/117",27);
    Student *s3 = new Student("Linda Mathews","GF/45/120",23);

    StudentCollection* sc = new StudentCollection();
    sc->Add(s1);
    sc->Add(s2);
    sc->Add(s3);

    IEnumerator* iEnum = sc->GetEnumerator();

    while(iEnum->MoveNext())
    {
        Student* stmp = dynamic_cast<Student*>(iEnum->Current);
        stmp->Display();
    }

    sc->Sort();
    iEnum->Reset();
    Console::WriteLine();    
    
    while(iEnum->MoveNext())
    {
        Student* stmp = dynamic_cast<Student*>(iEnum->Current);
        stmp->Display();
    }

    sc->SortByAge();
    iEnum->Reset();
    Console::WriteLine();    
    
    while(iEnum->MoveNext())
    {
        Student* stmp = dynamic_cast<Student*>(iEnum->Current);
        stmp->Display();
    }

    return 0;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Nish Sivakumar
United States United States
Member
Nish is a real nice guy who has been writing code since 1990 when he first got his hands on an 8088 with 640 KB RAM. Originally from sunny Trivandrum in India, he has been living in various places over the past few years and often thinks it’s time he settled down somewhere.
 
Nish has been a Microsoft Visual C++ MVP since October, 2002 - awfully nice of Microsoft, he thinks. He maintains an MVP tips and tricks web site - www.voidnish.com where you can find a consolidated list of his articles, writings and ideas on VC++, MFC, .NET and C++/CLI. Oh, and you might want to check out his blog on C++/CLI, MFC, .NET and a lot of other stuff - blog.voidnish.com.
 
Nish loves reading Science Fiction, P G Wodehouse and Agatha Christie, and also fancies himself to be a decent writer of sorts. He has authored a romantic comedy Summer Love and Some more Cricket as well as a programming book – Extending MFC applications with the .NET Framework.
 
Nish's latest book C++/CLI in Action published by Manning Publications is now available for purchase. You can read more about the book on his blog.
 
Despite his wife's attempts to get him into cooking, his best effort so far has been a badly done omelette. Some day, he hopes to be a good cook, and to cook a tasty dinner for his wife.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralInherit IEnumerable in C++ CLImemberMikeTheEvilTwin23 Jan '06 - 10:17 
Hi,
 
The new way to do things in CLI isn't clear in the matter of inheriting from IEnumerable<T>. Since IEnumerable<T> inherits from IEnumerable, two overrides are required when deriving from IEnumerable<T>:
 

1) System::Collections::IEnumerator^ GetEnumerator(void); (from System::Collections::IEnumerable)
 
2) System::Collections::Generic::IEnumerator<T>^ GetEnumerator(void); (from System::Collections::Generic::IEnumerable<T>)
 

The problem is we can't override both in the same class. You wil get those compile errors if you do so:
 
"overloaded function differs only by return type..."
"covariant returns types are not supported in managed types"
 
Overriding both functions is the only way to make things work so I need some tips on how to let the compiler understand what I'm doing.
 

Thank you so much for your time and efforts!
 

Mike
 

AnswerRe: Inherit IEnumerable in C++ CLImemberzaccheus5 May '06 - 11:52 
It's surprisingly simple.
 
Let's say you have a class called 'MyCollection' which holds instances of the class 'MyType'.
 
You just need to do the following:
 

////////////////////////////////////////////////////////////////
// .h

 
ref class MyCollection : public Generic::IEnumerable<MyType^>
{
public:
 
//...
 
// Tell compiler to use 'GetEnumeratorNonGeneric' as the implementation of
// System::Collections::IEnumerable::GetEnumerator

 
virtual System::Collections::IEnumerator^ GetEnumeratorNonGeneric() = System::Collections::IEnumerable::GetEnumerator;
 
// Also implement the generic interface
 
virtual Generic::IEnumerator<MyType^>^ GetEnumerator();
 
//...
 
private:
};
 
////////////////////////////////////////////////////////////////
// .cpp

 
System::Collections::IEnumerator^ MyCollection::GetEnumeratorNonGeneric()
{
return GetEnumerator();
}
 
Generic::IEnumerator<MyType^>^ MyCollection::GetEnumerator()
{
// ...
}

GeneralGreat articlememberfinoci26 Aug '05 - 6:11 
I browsed several articles before I came across yours and this really helped me understand these interfaces. Thanks for the lucid writing!
Questionmultiple classes in arraylist?memberalain cheng6 Jun '04 - 22:54 
i put 2 different classes in 1 arraylist
 
i got
class person:
string name
string birtday
 
and class student: derived of person
string name
string birthday
string room
 
this is the arraylist:
name_1 01/01/01
name_15 15/15/15 room15
name_3 03/03/03
name_4 04/04/04 room4
name_1 01/01/01
name_22 02/02/03 room22
^
how can i sort the student records of it, only that
GeneralThanks nish!memberMartin Häsemeyer4 Oct '03 - 22:25 
Your article helped a great deal! Smile | :) Got my 5!
 

Cheers
Martin
 
"Situation normal - all fu***d up"
Illuminatus!
 
http://www.martin-haesemeyer.de
Generalbug in MoveNextmemberJBoschen31 May '03 - 17:21 
this is a bug...
 
bool MoveNext()
{
if(m_sc->m_dirty)
throw new InvalidOperationException();

index++;
 
return (index < m_sc->m_students->Count);
}

 
Consider calling MoveNextenough so that index rotates back around to a valid number. (even worse, since it's signed, it goes past the max positive value and is now negative, thereby satisifying the condition)
 
index shouldn't be incremented unless the function is returning true
 
Small bug, yes, but things like this creep into production code and clients somehow find them.
 
Something like this is safe,
return ( index < m_sc->m_students->Count ? ++index, true : false );

GeneralExceptionmemberKarstenK28 Nov '02 - 4:26 
I know not much about the MC++ stuff, but in VC++ you must catch your thrown exception or they are unhandled. Confused | :confused:
 
Try this @ home. (B&B)
GeneralRe: ExceptioneditorNishant S28 Nov '02 - 14:39 
KarstenK wrote:
I know not much about the MC++ stuff, but in VC++ you must catch your thrown exception or they are unhandled.
 
The class methods throw exceptions which are to be caught and handled by the callee code (the client that consumes the class).
 
Regards,
Nish
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

QuestionWhat about STL?memberJason Orphanidis26 Jun '02 - 21:23 
C++ is known to have a huge advantage over all other languages, that being STL: container classes and algorithms, in a generic form, at the programmer's fingertips. STL drammatically boosted the quality of my projects, both in terms of development speed and of performance.
 
It seems a bit frustrating to me, seeing an article on how to build yet another container class (inventing the wheel all over again) and not mentioning the existance of the default "collection" library of C++, if not using it at the heart of its implementation. If the need is to produce a .NET compatible container/collection (whatever) class, why not wrap around a vector/list/map/set - you name it - STL class. They are dynamically resizable too, you know?! Poke tongue | ;-P
AnswerRe: What about STL?memberChristian Graus26 Jun '02 - 21:54 
Jason Orphanidis wrote:
It seems a bit frustrating to me, seeing an article on how to build yet another container class (inventing the wheel all over again) and not mentioning the existance of the default "collection" library of C++, if not using it at the heart of its implementation.
 
Sadly, you cannot use STL containers in managed C++ if you want interop. So far, I'm yet to see any evidence that what the .NET framework provides in it's stead is remotely comparable to the STL.

 
Christian
 
I am completely intolerant of stupidity. Stupidity is, of course, anything that doesn't conform to my way of thinking. - Jamie Hale - 29/05/2002
 
Half the reason people switch away from VB is to find out what actually goes on.. and then like me they find out that they weren't quite as good as they thought - they've been nannied. - Alex, 13 June 2002
GeneralRe: What about STL?memberJason Orphanidis26 Jun '02 - 22:13 
You mean you cannot declare:
 
std::vector<Object*> v;
v.push_back(&foo);
 
where foo is a .NET object?
Why not? memory allocation problem?
 
Even if this is the case (which I can't see why) STL can customize its memory allocation.
 
I'd really like to read an article on all the trade offs we'll have to put up with, to use .NET. Are they worth it?
GeneralRe: What about STL?memberChristian Graus26 Jun '02 - 23:14 
Jason Orphanidis wrote:
I'd really like to read an article on all the trade offs we'll have to put up with, to use .NET. Are they worth it?
 
Probably not, if you know C++. There is a thread on this below.
 
As to the problem, the issue is not what you put INTO the vector, it's the vector itself. If you want to write MC++ you can call from C#, STL is out. But MC++ is not C-- BECAUSE you get all the nowhere-near-as-good container stuff from Microsoft, who are the people who brought us CArray, so it must be good......
 


 
Christian
 
I am completely intolerant of stupidity. Stupidity is, of course, anything that doesn't conform to my way of thinking. - Jamie Hale - 29/05/2002
 
Half the reason people switch away from VB is to find out what actually goes on.. and then like me they find out that they weren't quite as good as they thought - they've been nannied. - Alex, 13 June 2002
GeneralRe: What about STL?memberNishant S29 Jun '02 - 21:53 
Christian Graus wrote:
But MC++ is not C-- BECAUSE you get all the nowhere-near-as-good container stuff from Microsoft, who are the people who brought us CArray, so it must be good......
 
LOL CG Smile | :)
 
Frankly I know so little of STL that I thought it wise not to do any comparisons Blush | :O
 

Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Review by Shog9
Click here for review[NW]

GeneralInvalidOperationException from IEnumeratormembersultan_of_6string20 Jun '02 - 17:39 
I see that you're using a flag (m_bDirty) to indicate whether the collection has been modified or not. However, picture this horrendous multi-threaded scenario:
 
The StudentCollection class is created.
Thread A calls GetEnumerator.
Thread B adds an item to the collection.
Thread B calls GetEnumerator.
 
The last call sets the flag to true, which is fine for Thread B but not for Thread A.
GeneralThat's cause of bad designmemberNishant S20 Jun '02 - 17:44 
sultan_of_6string wrote:
The StudentCollection class is created.
Thread A calls GetEnumerator.
Thread B adds an item to the collection.
Thread B calls GetEnumerator.

 
The issue here is that you are not doing implementing proper synchronization methods. When two threads access the same object it's the programmer who *should* make sure that the two threads don't access the shared object at the same time.
 
Nish
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

GeneralRe: That's cause of bad designmembersultan_of_6string20 Jun '02 - 18:51 
That's true, but then there's no point in giving IEnumerator the capability to throw InvalidOperationException.
 
If you use ildasm on mscorlib.dll to examine the IL behind ArrayList and it's nested enumerator classes, you'll find that it uses a private in32 field _version that's incremented each time the ArrayList is modified. When ArrayListEnumerator/ArrayListSimpleEnumerator is created, they save a local copy of _version--the state that the array was when the enumerator was created. Calls to Reset, MoveNext, etc. check to see that the local _version and the ArrayList's _version are the same.
 
This business of raising InvalidOperationExpection isn't for synchronization, but to tell bad programmers that they've screwed up! (actually, we all make mistakes) It's a lot of extra overhead for a C++ guy like me, but we've got to go along with the .NET philosophy.Smile | :)
GeneralRe: That's cause of bad designmemberNishant S20 Jun '02 - 19:07 
Hello Sultan
 
What you say is correct! Ideally it shouldn't be that way and I have a good guess that MS will change the docs in the next release. I feel that any number of enumerators for the same enumerable object should show similar behavior irrespective of context. But as you said the .NET philosophy is currently slightly different. Bit unfortunate in my opinion. I guess the way to implement this dirty flag business would be though an Int32 as you have said. Each time a modification is made this count is incremented. And any enumerators that are obtained will save this count value. Bit sloppy in my opinion.
 
Nish
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

GeneralRe: That's cause of bad designmembersultan_of_6string20 Jun '02 - 19:27 
I agree. It's a pretty messed up. Even the way MS has implemented it has potential problems in long running apps--apps that make over 4 billion changes in one run (i think that's the capacity of an Int32). I guess I'm really stretching it, but if they're trying to implement this feature of detecting lists that have been modified after the enumerator was created, they should do it right. I would recommend they kill this idea completely. It's too wierd to implement and has too much of an overhead. Let us programmers figure out when we're messing up.
GeneralRe: That's cause of bad designmemberNishant S20 Jun '02 - 20:17 
sultan_of_6string wrote:
Let us programmers figure out when we're messing up.
 
That sounds good. Though I am also in favour of the idea of all enumerators maintaining consistent outputs, though I realize the issues, rather serious issues too, in a multi threaded situation!
 
Nish
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

QuestionHOW TO: Implement Custom Collections in Visual C++ .NET (Q312514)memberAnonymous13 Jun '02 - 17:01 
http://support.microsoft.com/search/preview.aspx?scid=kb;en-us;Q312514
AnswerRe: HOW TO: Implement Custom Collections in Visual C++ .NET (Q312514)memberNish - Native CPian13 Jun '02 - 17:25 
Thanks for the link. Pretty nice article. Though it does not talk about IComparer and IComparable. But it does talk about ICollection. The example was not satisfactory though IMHO. It wasn't reflective of the capabilities of a collection like for example sorting facilities. Anyway, thanks once more Smile | :)
 
Regards
Nish
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Buy it, read it and admire me Smile | :)

GeneralRe: HOW TO: Implement Custom Collections in Visual C++ .NET (Q312514)subeditorJames T. Johnson13 Jun '02 - 18:39 
It also didn't correctly implement IEnumerator because it's implementation would allow the collection to be modified.
 
Nish, you're better than the KB! Smile | :)
 
James
GeneralRe: HOW TO: Implement Custom Collections in Visual C++ .NET (Q312514)memberNish - Native CPian13 Jun '02 - 18:39 
James T. Johnson wrote:
Nish, you're better than the KB!
 
Yeah Jig | [Dance]
 
wooohooooooooooooo Smile | :)
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Buy it, read it and admire me Smile | :)

GeneralI like it.memberShog913 Jun '02 - 15:52 
After spending two days this week in training, with all examples in either VB.NET or C#, it is *very* nice to read a .NET article with MC++ examples. Big Grin | :-D
 
--------

Hey you Whitehouse, ha ha, charade you are
You house proud town mouse, ha ha, charade you are

-- Pink Floyd, Pigs (Three Different Ones)


GeneralRe: I like it.memberNish - Native CPian13 Jun '02 - 17:17 
Shog9 wrote:
After spending two days this week in training, with all examples in either VB.NET or C#, it is *very* nice to read a .NET article with MC++ examples
 
Thanks Shog. I spend some more time on it than I usually do on my articles. Thanks to your suggestions Rose | [Rose]
 
Nish
 


Author of the romantic comedy

Summer Love and Some more Cricket [New Win]

Buy it, read it and admire me Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 13 Jun 2002
Article Copyright 2002 by Nish Sivakumar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid