I was a big fan of generics when they were first introduced in Java 5.0 and I have to say, .NET is no exception. In fact, I enjoy programming more in .NET these days than I do in Java. But that’s another story.When you can really abstract something well, the addition of generics can further afford your programming some more flexibility. One big use for generics is that of data structures/containers or collections. Lately I have made a lot of mileage from channels, developed as part of my concurrency utility set.Starting with a Bounded and Unbounded channel, I later had the need for a TimedChannel and ChannelCombiner. I decided to implement a generic channel interface so I could then use them all interchangeably.

Generics and interfaces

I have often found that when I start writing more than one generic class for a similar job, it calls out for a suitable generic interface. I don’t know why, but generics and interfaces just seem to sit so well.

public interface IChannel
{
    event EventHandler Changed;
    void Put(T toPut);
    bool TryPut(T toPut, TimeSpan timeout);
    bool TryTake(out T output, TimeSpan timeout);
    T Take();
    T[] Copy();
    int Count { get; }
    int Size { get; }
}

Make them interchangeable

You use generics for flexibility and code re-use. Make sure you provide the ability to move data between them freely. My timed channel made use of both a priority channel and an unbounded channel. The copy for this was slightly different as the data has to be extracted out of the priority list first, and then combined with the unbounded channel.

public T[] Copy()
{
    lock (_Lock)
    {
        T[] copy1 = _ReadyToTake.Copy();
        Task[] priorityCopy = _List.Copy();
 
        T[] copy2 = new T[priorityCopy.Length+copy1.Length];
        int index = 0;
 
        // Copy contents from both arrays in one pass.
        for (int i = 0; i 0 && copy1.Length > i && copy1[i] != null)
        {
             copy2[i] = copy1[i];
             else
               copy2[i] = priorityCopy[index++].Data;
         }
     return copy2;
}

The timed channel has to discard priority information when copying the data. Nevertheless, the actual data can easily be move to another IChannel. Say, a Bounded or UnBounded channel. Thus, after implementing a generic copy in each of the channels and data structures, channel interoperability was achieved :)

 What was next? - Generic Controls

With some nice generic channels that could all be passed around as IChannel. It was time for a generic .NET control that would display whatever was in the channel. This gave birth to a generic ChannelControl. The possibilities are endless. My time is not however :p

UnBoundedChannel<T>
BoundedChannel<T>
CombindedChannel<T>
TimedChannel<T>
ChanelControl<T>
PriorityListChannel<T>
 
// Interface to bring them alltogether
IChannel<T>