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:
- 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.
- 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.
- 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
- 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;
.
- 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.