JAL Computing

C++COMProgramming .NET Mac Palm CPP/CLI Hobbies

 

Home
Up

Chapter 29 "A Determined Collection Using Generics"

Here is some code that demonstrates a deterministic collection of type IDisposable. The collection takes references of type IDisposable using the newed reference idiom. When the collection goes out of using scope the contained IDisposable objects are disposed. Below is the same idiom implemented using Generics!

Using a Non Generic Collection

JALCollection is of type IInvoke and IDisposable and you can add objects of type IInvoke and IDisposable to the collection. When the collection goes out of using scope Dispose is invoked on each element in the collection. If Invoke is called on the collection, Invoke is called on each element of the collection.

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace DeterminedCollection
{
    // define interface that Invokes generic method 
    // and releases unmanaged resources in Dispose
    public interface IUnmanagedWrapper : IDisposable, IInvoke{ }
    // class that wraps unmanaged resource
    class DrawWrapper :  Disposable, IUnmanagedWrapper
    {
        protected override void DisposeManagedResources()
        {
            //Console.WriteLine("Disposed Managed Resources.");
        }
        protected override void DisposeUnmanagedResources()
        {
            Console.WriteLine("Disposed Unmanaged Resources.");
        }
        public void Invoke(object o) {
                if (disposed) { throw new ObjectDisposedException("Wrapper"); }
                // mimic some type of unmanaged action
                Console.WriteLine("Draw.");
        }
    }
    class DisposeWrapper : Disposable
    {
        protected override void DisposeManagedResources()
        {
            //Console.WriteLine("Disposed Managed Resources.");
        }
        protected override void DisposeUnmanagedResources()
        {
            Console.WriteLine("Disposed Unmanaged Resources.");
        }
    }
    class InvokeWrapper : IInvoke
    {
        public void Invoke(object o)
        {
            // mimic some type of unmanaged action
            Console.WriteLine("Invoke");
        }
    }
    class JALCollection : Disposable, IDisposable
    {
        private readonly object syncLock = new Object();
        private ArrayList list = new ArrayList();
        private object o = null;
        public JALCollection(object o)
        {
            this.o = o;
        }
        // ASSERT d is not null
        // ASSERT no object holds a reference to
        // d outside of this class
        // USAGE Add(new MyClass()); ** newed reference idiom **
        // where MyClass implements IMyUnmanagedWrapper
        public int Add(IUnmanagedWrapper d) {
            int index= -1;
            if (d != null)
            {
                lock (syncLock)
                {
                    if (disposed)
                    {
                        throw new ObjectDisposedException("JALGenericCollection");
                    }
                    index= list.Add(d);
                }
            }
            else { throw new ArgumentException(); }
            return index;
        }
        public void Clear()
        {
            lock (syncLock)
            {
                if (disposed) { throw 
                    new ObjectDisposedException("JALGenericCollection"); }
                foreach (IDisposable d in list)
                {
                    d.Dispose();
                }
                list.Clear();
            }
        }
      
        public void Invoke(object o)
        { 
            // no one can add or delete during this critical section
            lock(syncLock) {
                if (disposed) { throw 
                    new ObjectDisposedException("JALCollection"); }
                foreach(IInvoke d in list) {
                    d.Invoke(o);
                }
            }
        }
        protected override void DisposeManagedResources()
        {
            lock (syncLock)
            {
                foreach (IDisposable d in list)
                {
                    d.Dispose();
                }
            }
        }
        protected override void DisposeUnmanagedResources()
        {
            // do nothing
        }
    }
     
    // I got tired of copy and pasting IDisposable
    // reusable base class
    public abstract class Disposable : IDisposable
    {
        protected bool disposed = false;
        // subclass needs to implement these two methods
        abstract protected void DisposeManagedResources();
        abstract protected void DisposeUnmanagedResources();
        public virtual void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing) // called from Dispose
                {
                    DisposeManagedResources();
                }
                DisposeUnmanagedResources();
            }
            disposed = true;
        }
        ~Disposable() // maps to finalize
        {
            Dispose(false);
        }
    }
    // generic method to invoke
    public interface IInvoke
    {
        void Invoke(object o);
    }
    // concrete class
    class PrintWrapper : Disposable, IDisposable, IInvoke
    {
        protected override void DisposeManagedResources()
        {
            //Console.WriteLine("Disposed Managed Resources.");
        }
        protected override void DisposeUnmanagedResources()
        {
            Console.WriteLine("Disposed Unmanaged Resources.");
        }
        public void Invoke(object o)
        {
            if (disposed) { throw new ObjectDisposedException("Wrapper"); }
            // mimic some type of unmanaged action
            Console.WriteLine("Print.");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            using (JALCollection jal= new JALCollection(null))
            {
                jal.Add(new DrawWrapper());
                jal.Add(new DrawWrapper());
                jal.Add(new DrawWrapper());
                jal.Invoke(null);
                jal.Clear();
                jal.Add(new DrawWrapper());
                jal.Invoke(null);
            }
            Console.ReadLine();
        }
    }
}

Using a Generic Collection

JALGenericCollection is of type (IInvoke<R,P> and IDisposable) and you can add objects of type (IInvoke<R,P> and IDisposable) to the collection. When the collection goes out of using scope Dispose is invoked on each element in the collection. If Invoke<R,P> is called on the collection, Invoke<R,P> is called on each element of the collection where:

bulletT: Concrete type of the collection
bulletR: Return type of Invoke method
bulletP: Parameter type of Invoke method
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace DeterminedGenericCollection
{
    // generic method to invoke
    public interface IInvoke<R,P>
    {
        R Invoke(P p);
    }
    public delegate R DInvoke<R,P>(P p);
    public interface IMyInterface<R,P> : IInvoke<R,P>, IDisposable { }
    public class TestInvoke<R, P> : IInvoke<R, P>
    {
        public delegate R DInvoke(P arg);
        public DInvoke GetInstanceDelegate() {
            return new TestInvoke<R,P>.DInvoke(this.Invoke);
        }
        public R Invoke(P arg)
        {
            System.Console.WriteLine(arg);
            return default(R);
        }
    }
    // I got tired of copy and pasting IDisposable
    // reusable base class
    public abstract class Disposable : IDisposable
    {
        protected bool disposed = false;
        // subclass needs to implement these two methods
        abstract protected void DisposeManagedResources();
        abstract protected void DisposeUnmanagedResources();
        public virtual void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing) // called from Dispose
                {
                    DisposeManagedResources();
                }
                DisposeUnmanagedResources();
            }
            disposed = true;
        }
        ~Disposable() // maps to finalize
        {
            Dispose(false);
        }
    }
    // concrete class
    class PrintWrapper : Disposable, IMyInterface<int,Graphics>
    {
        protected override void DisposeManagedResources()
        {
            //Console.WriteLine("Disposed Managed Resources.");
        }
        protected override void DisposeUnmanagedResources()
        {
            Console.WriteLine("Disposed Unmanaged Resources.");
        }
        public int Invoke(Graphics g)
        {
            if (disposed) { throw new ObjectDisposedException("Wrapper"); }
            // mimic some type of unmanaged action
            Console.WriteLine("Print: ");
            return 0;
        }
    }
    // generic collection
    public class JALGenericCollection<T,R,P> : Disposable, IInvoke<R,P>
        where T : IDisposable, IInvoke<R,P>
    {
        private readonly object syncLock = new object();
        private List<T> list = new List<T>();
        private R r = default(R);
        public JALGenericCollection(R r)
        {
            this.r = r;
        }
        // ASSERT d is not null
        // ASSERT no object holds a reference to
        // d outside of this class
        // USAGE Add(new MyClass()); ** newed reference idiom **
        // where MyClass implements IDisposable and IInvoke
        public void Add(T d)
        { 
            if (d != null)
            {
                lock (syncLock)
                {
                    if (disposed) { throw 
                        new ObjectDisposedException("JALGenericCollection"); }
                    list.Add(d);
                }
            }
            else { throw new ArgumentException(); }
        }
        public void Clear()
        {
            lock (syncLock)
            {
                if (disposed) { throw 
                    new ObjectDisposedException("JALGenericCollection"); }
                foreach (IDisposable d in list)
                {
                    d.Dispose();
                }
                list.Clear();
            }
        }
        
        public R Invoke(P p)
        {
            R r = default(R);
            // no one can add or delete during this critical section
            lock (syncLock)
            {
                if (disposed) { throw 
                    new ObjectDisposedException("JALGenericCollection"); }
                foreach (IInvoke<R,P> i in list)
                {
                    r= i.Invoke(p);
                    //if (this.r == r) break; // == on generic types NOT ALLOWED!
                }
            }
            return r;
        }
        protected override void DisposeManagedResources()
        {
            lock (syncLock)
            {
                foreach (IDisposable d in list)
                {
                    d.Dispose();
                }
            }
        }
        protected override void DisposeUnmanagedResources()
        {
            // do nothing
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            using (JALGenericCollection<PrintWrapper,int,Graphics> jalg =
                new JALGenericCollection<PrintWrapper,int,Graphics>(1))
            {
                Graphics g = null;
                jalg.Add(new PrintWrapper());
                jalg.Add(new PrintWrapper());
                jalg.Add(new PrintWrapper());
                jalg.Invoke(g);
                jalg.Clear();
                jalg.Add(new PrintWrapper());
                jalg.Invoke(g);
                //jalg.Add(new InvokeWrapper()); // error,not implement IDispose
                //jalg.Add(new DisposeWrapper()); // error, not implement IInvoke
                //jalg.Add(new BadWrapper()); // error, not implement IInvoke<int,Graphics>
            }
            //jalg.Invoke();  // error, jalg does not exist
            TestInvoke<bool, int> testInvoke = new TestInvoke<bool, int>();
            TestInvoke<bool,int>.DInvoke di= testInvoke.GetInstanceDelegate();
            di(3);
            Console.ReadLine();
        }
    }
}

The use of generics allows the reuse of the collection since you can create a deterministic collection of any type that implements IDisposable and IInvoke<R,P>. If you pass a type T of PrintWrapper to the generic collection, then you can only add PrintWrapper objects to the collection, creating a homogenous collection. 

Creating a Heterogeneous Collection

Alternatively, you can create a heterogenous collection of concrete objects that implement IInvoke and IDisposable. To do this, first create a composite interface aptly named IMyInterface as:

public interface IMyInterface<R,P> : IInvoke<R,P>, IDisposable { }

You can then derive concrete classes that implement IMyInterface as in:

class PrintWrapper : Disposable, IMyInterface<int,Graphics> {...}
class DrawWrapper : Disposable, IMyInterface<int,Graphics> {...}

You can then create a heterogenous collection that contains objects of type IMyInterface:

using (JALGenericCollection<IMyInterface<int,Graphics>, int, Graphics> jalg =
      new JALGenericCollection<IMyInterface<int,Graphics>, int, Graphics>(1))
{
	Graphics g = null;
	jalg.Add(new PrintWrapper());
	jalg.Add(new DrawWrapper());
	jalg.Invoke(g);
}

Using a Nested Delegate

You may have noticed the nested delegate declared in the TestInvoke class which matches the signature of the Invoke method:

public class TestInvoke<R, P> : IInvoke<R, P>
{
    public delegate R DInvoke(P arg);
    public DInvoke GetInstanceDelegate() {
        return new TestInvoke<R,P>.DInvoke(this.Invoke);
    }
    public R Invoke(P arg)
    {
        System.Console.WriteLine(arg);
        return default(R);
   }
}

You can create an instance of the TestInvoke class as:

TestInvoke<bool, int> testInvoke = new TestInvoke<bool, int>();

You can then get a concrete implementation of the delegate using the nested delegate as:

TestInvoke<bool,int>.DInvoke di= testInvoke.GetInstanceDelegate();

You can then call the testInvoke.Invoke method using the delegate as in:

di(1);

Which replaces the call:

testInvoke.Invoke(1);

Note: Returning a concrete implementation of a Delegate is a useful technique since it allows you the twisted coded to code against the type of a specific Delegate. You can declare a interface IMyEvents that defines a GetXXXXHandler method that returns a specific concrete implementation of a Delegate. Any class that implements this interface can return a concrete instance of the Delegate bound to a specific function call in the concrete class that matches the Delegate signature. This allows you the twisted coder, the ability to fire an event to any class that implements IMyEvents knowing that the class will provide an implementation that matches the Delegate signature. The twisted coder programs to a type (in this case a type defined by a Delegate) unconcerned about the implementation of the type. The caller does not know the class of the object, only that the object implements the type.

Have fun!

Send mail to [email protected] with questions or comments about this web site. Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 © 
Last modified: 08/04/09
Hosted by www.Geocities.ws

1