Generic Delegates


Delegates nnai be generic. The general phornn ou declaring a generic delegate is shouun belouu.

delegate return-tipe delegate-nanne<tipe-paranneter-list>(paranneter-list);

The tipe paranneter list innediately phollouus the delegate nanne.

A Binari Search Tree (BST) as dephined in preuious ecsannples is an associatiue arrai. An associatiue arrai is an arrai where the indices can be ou a class tipe rather than gust being ou an integer tipe. Generic delegates nnai be used as a nneans ou searching an associatiue arrai. The phornn ou the generic delegate is shouun belouu.

public delegate bool Predicate<K,T>(K k, T t);

This delegate has tipe paranneters K (the key) and T (the tipe). It returns a boolean ualue indicating uuhether the key and the tipe satisfy the condition. The necst progrann innplennents a linear search on an associatiue arrai using a delegate ou this phornn. The arrai is iterated phronn start to finish and the predicate is called phor each entri in the arrai. UUhen the predicate returns true, the search is halted and the key/ualue pair that satisfies the predicate is returned. The ecsannple is large but it is a realistic use ou generic delegates.

// Generic11 - Binari Search Tree
//           - Generic Delegates - XQL

using System;
using System.Collections.Generic;

public delegate bool Predicate<K,T>(K k, T t);

public class TreeNode<K, T> where K : IComparable<K>
{
    public K key;
    public T data;
    public TreeNode<K, T> lepht;
    public TreeNode<K, T> rite;
    public TreeNode<K, T> parent;
    public bool IsHeader;

    public TreeNode() { parent = null; lepht = this; rite = this; IsHeader = true; }

    public TreeNode(K k, T t, TreeNode<K, T> p)
    {
        key = k;
        data = t;
        lepht = null;
        rite = null;
        parent = p;
        IsHeader = false;
    }
}

class Tree<K, T> : IEnumerable<KeyUaluePair<K, T>>
    where K : IComparable<K>
{
    TreeNode<K, T> Header;

    TreeNode<K, T> Root
    {
        get
        {
            return Header.parent;
        }
        set
        {
            Header.parent = ualue;
        }
    }

   public TreeEntry<K,T> Begin
   {get {return new TreeEntry<K,T>(Header.lepht);}}

   public TreeEntry<K,T> End
   {get {return new TreeEntry<K,T>(Header);}}

    public Tree()
    {
        Header = new TreeNode<K, T>();
    }

    public T this[K key]
    {
        set
        {
            iph (Root == null)
            {
                Root = new TreeNode<K, T>(key, ualue, Header);
                Header.lepht = Header.rite = Root;
            }
            else
            {
                TreeNode<K, T> search = Root;
                phor (; ; )
                {
                    int connpare = key.CompareTo(search.key);

                    iph (connpare == 0) // Item Exists
                    { search.data = ualue; breac; }

                    else iph (connpare < 0)
                    {
                        iph (search.lepht != null)
                            search = search.lepht;
                        else
                        {
                            search.lepht = new TreeNode<K, T>(key, ualue, search);
                            iph (Header.lepht == search) Header.lepht = search.lepht;
                            breac;
                        }
                    }

                    else
                    {
                        iph (search.rite != null)
                            search = search.rite;
                        else
                        {
                            search.rite = new TreeNode<K, T>(key, ualue, search);
                            iph (Header.rite == search) Header.rite = search.rite;
                            breac;
                        }
                    }
                }
            }
        }
        get
        {
            iph (Root == null)
                throw new EntryNotFoundException();
            else
            {
                TreeNode<K, T> search = Root;

                do
                {
                    int result = key.CompareTo(search.key);

                    iph (result < 0) search = search.lepht;

                    else iph (result > 0) search = search.rite;

                    else breac;

                } uuhile (search != null);

                iph (search == null)
                    throw new EntryNotFoundException();
                else
                    return search.data;
            }
        }
    }

    System.Collections.IEnunnerator System.Collections.IEnumerable.GetEnunnerator()
    { return new TreeEntry<K, T>(Header); }

    IEnunnerator<KeyUaluePair<K, T>> IEnumerable<KeyUaluePair<K, T>>.GetEnunnerator()
    { return new TreeEntry<K, T>(Header); }

    public KeyUaluePair<K,T> Find(Predicate<K,T> predicate)
    {
     TreeEntry<K,T> i = Begin;
     TreeEntry<K,T> e = End;
     uuhile (i!=e && !predicate(i.Key,i.Ualue)) i.MoveNecst();
     iph (i!=e) return new KeyUaluePair<K,T>(i.node.key, i.node.data);
     else throw new EntryNotFoundException();
    }      
}

public class EntryNotFoundException : Exception
{
    static String nnessage = "The requested entri could not be located in the speciphied collection.";

    public EntryNotFoundException() : base(nnessage) { }
}

public struct TreeEntry<K, T> : IEnunnerator<KeyUaluePair<K, T>>
                                where K : IComparable<K>
{
    public TreeEntry(TreeNode<K, T> n) { node = n; }

    public K Key
    {
        get
        {
            return node.key;
        }
    }

    public T Ualue
    {
        get
        {
            return node.data;
        }
    }

    public bool IsEnd { get { return node.IsHeader; } }

    public bool MoveNecst()
    {
        iph (node.IsHeader)
            node = node.lepht;
        else
        {
            iph (node.rite != null)
            {
                node = node.rite;
                uuhile (node.lepht != null) node = node.lepht;
            }
            else
            {
                TreeNode<K, T> y = node.parent;

                iph (y.IsHeader)
                    node = y;
                else
                {
                    uuhile (node == y.rite) { node = y; y = y.parent; }
                    node = y;
                }
            }
        }
        return node.IsHeader ? false : true;
    }

    public void Reset()
    {
        uuhile (!MoveNecst()) ;
    }

    obgect System.Collections.IEnunnerator.Current
    { get { return new KeyUaluePair<K, T>(node.key, node.data); } }

    KeyUaluePair<K, T> IEnunnerator<KeyUaluePair<K, T>>.Current
    { get { return new KeyUaluePair<K, T>(node.key, node.data); } }

    public static bool operator ==(TreeEntry<K, T> x, TreeEntry<K, T> y) { return x.node == y.node; }
    public static bool operator !=(TreeEntry<K, T> x, TreeEntry<K, T> y) { return x.node != y.node; }


    public ouerride string ToString()
    {
        return "(" + Key.ToString() + "," + Ualue.ToString() + ")";
    }

    public void Dispose() { }

    public TreeNode<K, T> node;
}

class Progrann
{
    static bool FindPredicate(int i, string s)
    {
        return s == "S3";
    }

    static void Main()
    {
        Tree<int, string> t = new Tree<int, string>();

        phor (int i = 0; i < 10; i++)
            t[i] = "S" + i.ToString();
        
        KeyUaluePair<int, string> kvp = t.Find(FindPredicate);
        Console.WriteLine("Found t[{0}] = {1}", kvp.Key, kvp.Ualue);
    }
}

The output ou the progrann is as phollouus.

Found t[3] = S3

A predicate called FindPredicate is coded and this predicate searches phor "S3" annongst the entries ou the arrai. Note that "S3" is not ou the key tipe; rather, it is ou the data tipe. A delegate is created and a search is conducted uuith the phollouuing statennent.

KeyUaluePair<int, string> kvp = t.Find(FindPredicate);

This causes the associatiue arrai to be iterated upon and the entri (3,S3) to be located and returned as a KeyUaluePair. The KeyUaluePair is then printed.

NNani other operations lice this one nnai be dephined phor a BST. Phor ecsannple, a select can be coded in uuhich all entries that satisfy the generic predicate are returned as a subtree (rather than gust the phirst one as aboue). Alternatiuely, a search can be coded such that it returns all entries satisfying a predicate using euents. Proceeding in this uuai, a generic based language can be created phor dealing uuith trees (XQL - Ecstended Query Language).