Using Delegates to Choose Right Function


The need to call different class method based on some string passed to class is an old problem. Suppose that you have some query processor, that should run different queries depending on query name:

public class Query
{
public string name;
public Hashtable parameters;
}

In the old days you were used to write bunch of comparisons to find the right query processor method, like this:

public class QueryProcessor
{
public QueryProcessor()
{
}
public bool RunQuery( Query query )
{
if( query.name == "Query1" )
return RunQuery1( query );
if( query.name == "Query2" )
return RunQuery2( query );
// Query not found
throw new Exception( "Query " + query.name + " not found.");
}
public bool RunQuery1( Query query )
{
// Do something
return true;
}
public bool RunQuery2( Query query )
{
// Do something else
return true;
}
}

Pretty boring, right? And imagine that you have not two, but twenty query functions... But, lucky enough, we are able to shorten the code a bit. Actually, there is two different ways to achieve needed result without doing comparisons - reflection and delegates. Let's look at delegates - it is very quick and easy solution.

First of all, we will need to declare a delegate for our query processing methods:

public delegate bool QueryMethod( Query query );

Next, we should declare Hashtable, which will hold mappings between query names and query processing methods. You can declare it as member variable in class QueryProcessor:

public class QueryProcessor
{
private Hashtable queryTable;
....
}

Then we need to create and feel this
hashtable with mappings. Let's do it in a constructor:

public class QueryProcessor
{
public QueryProcessor()
{
queryTable =
new Hashtable();
// Creating mappings
queryTable.Add( "Query1", new QueryMethod(this.RunQuery1));
queryTable.Add( "Query2",
new QueryMethod(this.RunQuery2));
}
}

And the last final touch - we need to rewrite RunQuery method to use those mappings:

public class QueryProcessor
{
public bool RunQuery( Query query )
{
// Looking-up a delegate in the table
QueryMethod qm = (QueryMethod) queryTable[query.name];
if( qm == null )
{
// No method found - throwing an exception
throw new Exception( "Query " + query.name + " not found." );
}
// Running delegate to call a right function
return qm( query );
}
}

That's it! All you need to do to implement one more query is to write processing method and add another mapping into queryTable.

Below you can find full code of this example.

namespace QueryTest
{
using System;
using System.Collections;
public class Query
{
public string name;
public string parameters;
}
public delegate bool QueryMethod( Query query );
public class QueryProcessor
{
private Hashtable queryTable;
public QueryProcessor()
{
queryTable =
new Hashtable();
queryTable.Add( "Query1",
new QueryMethod(this.RunQuery1));
queryTable.Add( "Query2",
new QueryMethod(this.RunQuery2));
}
public bool RunQuery( Query query )
{
QueryMethod qm = (QueryMethod) queryTable[query.name];
if( qm == null )
throw new Exception( "Query "+query.name+" not found." );
return qm( query );
}
private bool RunQuery1( Query query )
{
return true;
}
private bool RunQuery2( Query query )
{
return false;
}
}
public class Test
{
public static void Main( string[] args )
{
Query query =
new Query();
QueryProcessor processor =
new QueryProcessor();
bool result;
query.name = "Query1";
try
{
result = processor.RunQuery( query );
}
catch( Exception ex )
{
Console.WriteLine( ex.Message );
}
}
}
}


Similar Articles