Wrox Programmer Forums
Go Back   Wrox Programmer Forums > C# and C > C# 1.0 > C#
|
C# Programming questions specific to the Microsoft C# language. See also the forum Beginning Visual C# to discuss that specific Wrox book and code.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the C# section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old May 10th, 2006, 06:49 PM
Authorized User
 
Join Date: May 2006
Posts: 25
Thanks: 0
Thanked 0 Times in 0 Posts
Default IEnumerator & Dynamic (run-time) Casting.

Picture this scenario. You have two indexer classes that both implement IEnumerable. You know that the valid index range is in [0,1]. Due to the nature of the project, the two classes do not and will not have a base class. You then have two classes that build lists on these indexers, each of which extends a base class, which includes an abstract function to return an IEnumerable result.

class ClassA : IEnumerable
{
   // n is valid in [0,1]
   public this[int n] { get { ... } set { ... } }
}

class ClassB : IEnumerable
{
   // n is valid in [0,1]
   public this[int n] { get { ... } set { ... } }
}


abstract class ListBase
{
   abstract IEnumerable GetList ();
}

class ListA : ListBase
{
   override IEnumerable GetList { return list; }
}

class ListB : ListBase
{
   override IEnumerable GetList { return list; }
}


Let's imagine that you wanted to build an HTML SELECT box on these lists. You might declare a variable of type ListA and a variable of type ListB, and process them. This is easy to do:

ListA A = new ListA();
ListB B = new ListB();

IEnumerable resultsA = A.GetList();
for (ListA rA in resultsA)
   outHTML_A = "<option value='" + rA[0] + '">" + rA[1] + "</option>";


IEnumerable resultsB = B.GetList();
for (ListB rB in resultsB)
   outHTML_B = "<option value='" + rB[0] + '">" + rB[1] + "</option>";


Now tweak the scenario a bit. You don't know at compile time which list will need to be turned into a SELECT box. You want to be able to declare a variable of type ListBase, and then at run-time call the GetList function and build your options list. The immediate problem is illustrated below (in the form of ????).

ListBase C;

// C has been set at run time to an instance of either ListA or ListB
IEnumerable resultsC = C.GetList();
for (???? rC in resultsC)
   outHTML = "<option value='" + rC[0] + '">" + rC[1] + "</option>";

You don't know at run-time which indexer (ClassA or ClassB) is in the result set, but you need to know in order to both use the for (... in ...) iterator and access the indexers. You really would like to avoid writing a switch statement to determine which class it was, especially since you might add ClassC, ListC and ClassD, ListD, etc. in the future. Here-in lies a solid use for dynamic (run-time) casting. Can it be done, and how would you evaluate the type held inside the result set to know how to cast rC?

This is similar to what I'm actually doing using ASP.NET DataSets & TableAdapters. The key is that processing of the list happens in the base class, since it is the same regardless of which child class invoked the processing method.



Brandon
__________________
Brandon
 
Old May 11th, 2006, 05:17 PM
Authorized User
 
Join Date: May 2006
Posts: 25
Thanks: 0
Thanked 0 Times in 0 Posts
Default

More bloat for the ware.

Since it is not possible to know whether the contents of the IEnumerable resultC is of type ClassA or ClassB, it is necessary to make a third class that acts as a sort of wrapper. Here is a rough example of how I solved the problem for my own project.

struct ClassW
{
    public string A;
    public string B;
    public string this[int i] { get { return i == 0 ? A : B; } }
    public ClassW ( string a, string b ) { A = a; B = b; }
}

To keep it simple for my own project, I skipped IEnumerable, opting instead to deal with ArrayList. Thus, I had to change the prototype for GetList() to return ArrayList instead of IEnumerable. I should point out that the child classes were calling a TableAdapter to get the result sets, which was why the return values were restricted to IEnumerable, and why the contents of the results were of unrelated datatypes (remember that in this example ClassA and ClassB are unrelated).

abstract class ListBase
{
   abstract ArrayList GetList ();
}

class ListA : ListBase
{
   override ArrayList GetList ()
   {
      ArrayList o = new ArrayList ();

      IEnumerable list = sourceA.GetData();
      foreach (ClassA a in list)
         o.Add (new ClassW (a[0].ToString(), a[1].ToString());

      return o;
   }
}

class ListB : ListBase
{
   override ArrayList GetList ()
   {
      ArrayList o = new ArrayList ();

      IEnumerable list = sourceB.GetData();
      foreach (ClassB b in list)
         o.Add (new ClassW (b[0].ToString(), b[1].ToString());

      return o;
   }
}

This does lead to a bit of code redundancy and overhead (these are the choices you make when you take full advantage of interfaces, polymorphism, inhertance, etc.), but in my project it is less redundancy than if i did all of the processing of the lists in the child classes. Now the base class can process the lists, relying upon the child class GetList implementations:

abstract class ListBase
{
   abstract ArrayList GetList ();

   void ProcessList()
   {
      ArrayList result = this.GetList(); // THANK YOU POLYMORPHISM!
      foreach (ClassW in result)
      {
          process away, and who cares whether this was ClassA or ClassB because
          the resulting ArrayList contains only data of type ClassW (as long
          as the child classes were written correctly!)

          this is lots of processing code that is exactly the same regardless
          of ListA or ListB, and I'd hate to see it repeated in every
          inherited class. Also, I can now add ListC and ListD without
          too much extra effort.
      }
   }
}


Brandon





Similar Threads
Thread Thread Starter Forum Replies Last Post
Insert Query Error & Run-Time Error 3022 DavidWE Access 1 July 31st, 2008 11:17 AM
Dynamic Casting? gman997 C# 3 February 11th, 2008 06:11 PM
time zone & day light time rajn ASP.NET 1.0 and 1.1 Professional 0 August 7th, 2007 05:02 PM
Add static controls in run time & change font/bkg firstreflex Visual C++ 0 December 17th, 2004 12:24 PM
Dynamic Casting pareshsoft C# 2 December 1st, 2004 12:12 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.