Saturday, February 04, 2006

Generic Sets and Collection Wrapper


Introduction


This simple library is developed for working with NHibernate 1.1 or lower. If there is no benefit of having a generic Set<T> that also implements Iesi.Collections.ISet from NHibnernate, you might be more interested in the C5 collection library or the PowerCollection.


This is a simple extension to JasonSmith's Iesi.Collections to offer a generic version of the ISet and its implementations. Also included are five wrappers which help in using old non-generic collections as generic collections. This could be helpful if you want to wrap a non-generic collection from an old application as generic ones in your application.


Like in .NET 1.1, there is need for a generic ISet in the .NET 2.0 environment. There are already some implementations based on JasonSmith's famous Iesi.Collections.ISet. One of them was found on NHibernate' JIRA which is, according to G77 (thanks!), authored by David Marquam. The implementation of this article is basically a modified version of that implementation. I would like to make it clear that most of the credit of this extension goes to him. I posted this version here so that more people can take advantage of this nice work.


However, David's implementation could not perfectly meet our needs because of several facts:



  1. The ISet<T> in this implementation also inherits the ISet. This inheritance caused the lost of the type safe characteristic that a generic collection normally has.
  2. The ISet<T> does not have the bool Add(T o) method like the ISet has. It only has the void ICollection<T>.Add(T o); the ability to tell whether the item has been actually added might be missed.
  3. The generic extension was included in the assembly of JasonSmith’s Iesi.Collection, which makes some difficulty in working with the original Iesi.Collection.

Using the code


Thus I decided to modify this implementation so that the ISet<T> looks like the following:

public interface ISet<T> : ICollection<T>, ICloneable {…}

In the meantime, I think it could be very helpful if the base Set class still implements the ISet interface since it has been widely applied, including by NHibernate. In this way, you can still have the collection mapped by NHibernate.

public abstract class Set<T> : ISet<T>, ISet {…}

As a reminder, here is the declaration of ISet from Iesi.Collections:

public abstract class ISet : ICollection, ICloneable {…}

For the usage of this ISet<T>, please refer to JasonSmith's article about his Iesi.Collections.


Since Set<T> brought the scenario where a generic collection needs to work with old non-generic collections, I added five simple wrappers:

public struct EnumeratorWrapper<T> : IEnumerator<T>{…}
public class EnumerableWrapper <T> : IEnumerable<T>
public sealed class SetWrapper<T> : ISet<T>
public class CollectionWrapper<T> : EnumerableWrapper<T>, ICollection<T>
public class ListWrapper<T> : EnumerableWrapper<T>, IList<T>

These wrappers support using regular collections under a generic collection interface by wrapping the regular collection as an inner collection and delegate all the functions to it. Also, the Equals() of the wrapper are also overridden to delegate to the wrapped, so that wrapperA.Equals(wrapperB) will return true when and only when wrappedA.Equals(wrappedB) is true. The usage of these wrappers are very simple, here is a sample code:

IList = new ArrayList(3);
list.Add("one");
list.Add("two");
list.Add("three");

ICollection<string> cln = new CollectionWrapper<string>(list);
IEnumerable<string> enl = new EnumerableWrapper<string>(list);
IList<string> lst = new ListWrapper<string>(list);

The Iesi.Collections.Generic is in an independent assembly so that use can have more flexibility with using this together with the Iesi.Collection.Generic.


I will keep working on the implementations since my development greatly relies on them.


Important Notes



  1. This implementation is based on the source code from NHibernate which does not override the Equals method, so the a.Equals(b) in this implementation will only return true if a==b;.
  2. The generic SynchornoizedSet has not been implemented yet.

Latest Update:


Feb 6, 06


I added the Iesi.Collections.Test from Nhibernate1.0.2.0. 67 out of the 87 tests were passed using the generic implementation.


The four ExclusiveOR tests could not be passed before I did a very minor modification to the original Iesi.Collections: in the original Set, the method ExclusiveOr was written as follows:

public static ISet ExclusiveOr(ISet a, ISet b)
{
if(a == null && b == null)
return null;
else if(a == null)
return (Set)b.Clone();
else if(b == null)
return (Set)a.Clone();
else
return a.ExclusiveOr(b);
}

Note that the clones of a and b are unnecessarily down cast to Set. While, in the Union method of this class, these two clones are down cast to ISet. I modify the original code as follows:

return (ISet)b.Clone();
...
return (ISet)a.Clone();

After this modification, the Iesi.Collection still passes all the Iesi.Collection.Test, and the generic implementation also passes the four ExclusiveOr tests.


Latest update: This small bug of Iesi.Collection.Set has been fixed in the NHibernate version 1.1-alpha1 [ 10081 ], so you don't need to worry about this problem if you are using Iesi.Collection from the later versions of NHibernate.


There are still 16 tests that cannot be passed. They are all operator tests. Since operators can only be used between classes not interfaces, the operator tests down cast the ISet to Set to do the tests, and our generic implementation cannot be downcast to the non-generic Set which causes the failure of the 16 tests.

2 comments:

  1. Anonymous6:17 AM

    Hello !.
    You re, I guess , probably very interested to know how one can collect a huge starting capital .
    There is no need to invest much at first. You may begin earning with as small sum of money as 20-100 dollars.

    AimTrust is what you haven`t ever dreamt of such a chance to become rich
    The company represents an offshore structure with advanced asset management technologies in production and delivery of pipes for oil and gas.

    It is based in Panama with structures everywhere: In USA, Canada, Cyprus.
    Do you want to become an affluent person?
    That`s your chance That`s what you desire!

    I feel good, I started to get income with the help of this company,
    and I invite you to do the same. It`s all about how to select a proper partner utilizes your money in a right way - that`s AimTrust!.
    I earn US$2,000 per day, and my first investment was 500 dollars only!
    It`s easy to join , just click this link http://ymafopuqo.freewaywebhost.com/xivyhu.html
    and go! Let`s take our chance together to feel the smell of real money

    ReplyDelete
  2. Anonymous1:43 PM

    Hi !.
    You re, I guess , perhaps very interested to know how one can collect a huge starting capital .
    There is no initial capital needed You may begin to get income with as small sum of money as 20-100 dollars.

    AimTrust is what you haven`t ever dreamt of such a chance to become rich
    The company represents an offshore structure with advanced asset management technologies in production and delivery of pipes for oil and gas.

    Its head office is in Panama with structures everywhere: In USA, Canada, Cyprus.
    Do you want to become really rich in short time?
    That`s your chance That`s what you wish in the long run!

    I`m happy and lucky, I started to get real money with the help of this company,
    and I invite you to do the same. If it gets down to select a proper companion who uses your funds in a right way - that`s AimTrust!.
    I earn US$2,000 per day, and what I started with was a funny sum of 500 bucks!
    It`s easy to join , just click this link http://acexasetum.kogaryu.com/kivexa.html
    and go! Let`s take this option together to get rid of nastiness of the life

    ReplyDelete