generics - c# - Store a collection of handlers mapped to the concrete type they operate on -


i adding metrics tracking application. each concrete metric object there specific metricstracker responsible parsing data , sending off server. wanted use generics each metricstracker, ran issue during design, , cannot figure out elegant solution. i've created simplified model illustrate stuck.

lets pretend running a zoo, when notice 1 of animals sick, need find zoo keeper specializes in caring animal.

here animal class. contains zoocode used zoo identify it. (note "zoocode" necessary in real model because identifies metric type on server)

public abstract class animal {     //the zoo code of animal.      public abstract int zoocode { get; }      //other things specific animal.  } 

here example of concrete animal.

public class elephant : animal {     //an elephant has zoo code of 1     public override string zoocode { { return 1; } } } 

here base class zookeeper, zookeeper knows how care specific type of animal.

public abstract class zookeeper {     //the zoo code of animal care for.      public abstract int animaltendsto { get; }      //tend our animals needs     public abstract void careforanimal(animal animal); } 

here example of concrete zookeeper.

public class elephantkeeper : zookeeper {     //we care elephants, have zoocode of '1'      public override int animaltendsto     {         { return 1; }     }      public override void careforanimal(animal animal)     {         //cast animmal elephant, feed peanuts.     } } 

now when notice animal sick, go zookeepermanagers office , tell them animal needs treated. responsibility of zookeepermanager find zookeeper specializes in sick animal.

public class zookeepermanager {        /// <summary>     /// of zookeepers, mapped zoocode of animal      /// care for.      /// </summary>     private dictionary<int, zookeeper> _zookeepers;      /// <summary>     /// called when hire new zoo keeper.      /// </summary>     public void registerzookeeper(zookeeper newbie)     {         //data validation, etc...          //store our new zookeeper.          _zookeepers.add(newbie.animaltendsto, newbie);     }       public void careforanimal(animal animal)     {         //an animal needs care, find zookeeper can care it.          zookeeper caretaker;          if (_zookeepers.trygetvalue(animal.zoocode, out caretaker) == false)             return;          caretaker.careforanimal(animal);      } } 

here unhappy design! intended zookeeper generic, way zookeeper got reference concrete animal cared for, , didn't have worry specifying zoocodes or casting animal correct type. here first came with..

public abstract class zookeeper<t>     t : animal {     //tend our animals needs     public abstract void careforanimal(t animal); } 

a zookeepermanager needs know zookeepers care animal.. idea of zookeepermanager being able "oh elephant sick?? means need zookeeper" couldn't figure out elegant way store zookeepers when generic. got stuck:

public class zookeepermanager {        /// <summary>     /// of zookeepers, mapped zoocode of animal      /// care for.      /// </summary>     private list<zookeeper<animal>> _zookeepers;      /// <summary>     /// called when hire new zoo keeper.      /// </summary>     public void registerzookeeper(zookeeper<animal> newbie)     {         //data validation, etc...          //store our new zookeeper.          _zookeepers.add(newbie);     }       public void careforanimal(animal animal)     {         //how find zoo keeper cares animal??          //a list isn't want.. won't have o(1) lookup, plus how know         //which concrete animal zookeeper cares about?     } }  

does have ideas how store collection in zookeepermanager maps zookeeper type of animal care for?

ok, yes, it's possible, first must implement base zookeeper:

public class zookeeperbase { } 

and abstract zookeeper must inherit it:

public abstract class zookeeper<t> : zookeeperbase t : animal {     //tend our animals needs     public abstract void careforanimal(t animal); } 

finally modify manager store zookeeperbase's instances , use boxing , generic function when must take care of animal:

private list<zookeeperbase> _zookeepers = new list<zookeeperbase>();  public void careforanimal<t>(t animal) t : animal     {         //how find zoo keeper cares animal??          //a list isn't want.. won't have o(1) lookup, plus how know         //which concrete animal zookeeper cares about?          foreach (zookeeperbase keeper in _zookeepers)         {              var thiskeeper = keeper zookeeper<t>;              if (thiskeeper != null)             {                  thiskeeper.careforanimal(animal);                 return;              }          }     } 

for clarity i'm posting full model , test class.

public abstract class animal {     //the zoo code of animal.      public abstract int zoocode { get; }      //other things specific animal.  }  public class elephant : animal {     //an elephant has zoo code of 1     public override int zoocode { { return 1; } } }  public class zookeeperbase { }  public abstract class zookeeper<t> : zookeeperbase t : animal {     //tend our animals needs     public abstract void careforanimal(t animal); }  public class elephantkeeper : zookeeper<elephant> {     public override void careforanimal(elephant animal)     {         console.writeline("hi elephant! take peanuts.");     } }  public class zookeepermanager {     /// <summary>     /// of zookeepers, mapped zoocode of animal      /// care for.      /// </summary>     private list<zookeeperbase> _zookeepers = new list<zookeeperbase>();      /// <summary>     /// called when hire new zoo keeper.      /// </summary>     public void registerzookeeper(zookeeperbase newbie)     {         //data validation, etc...          //store our new zookeeper.          _zookeepers.add(newbie);     }       public void careforanimal<t>(t animal) t : animal     {         //how find zoo keeper cares animal??          //a list isn't want.. won't have o(1) lookup, plus how know         //which concrete animal zookeeper cares about?          foreach (zookeeperbase keeper in _zookeepers)         {              var thiskeeper = keeper zookeeper<t>;              if (thiskeeper != null)             {                  thiskeeper.careforanimal(animal);                 return;              }          }     } }  public static class zookeepingsystemtest {       public static void keepit()     {         zookeepermanager manager = new zookeepermanager();          elephantkeeper keeper = new elephantkeeper();          manager.registerzookeeper(keeper);          manager.careforanimal(new elephant());      }  } 

edit: did not noticed comment not using list, indeed possible, in example i'm using dictionary store list of zookeepers take care of concrete animal can use of them randomly (if have keeper each animal type can add keeper directly dictionary), zookeepermanager must modified.

public class zookeepermanager {     /// <summary>     /// of zookeepers, mapped animal's full class name     /// care for.      /// </summary>     private dictionary<string, list<zookeeperbase>> _zookeepers = new dictionary<string, list<zookeeperbase>>();      /// <summary>     /// called when hire new zoo keeper.      /// </summary>     public void registerzookeeper<t>(zookeeper<t> newbie) t : animal     {         //data validation, etc...          var type = typeof(t);          list<zookeeperbase> keeperpool = null;          if (_zookeepers.containskey(type.fullname))             keeperpool = _zookeepers[type.fullname];         else         {              keeperpool = new list<zookeeperbase>();             _zookeepers.add(type.fullname, keeperpool);         }          //store our new zookeeper.          keeperpool.add(newbie);     }       public void careforanimal<t>(t animal) t : animal     {          var type = typeof(t);          if (!_zookeepers.containskey(type.fullname))             throw new exception("we don't know how care animal!");          random rnd = new random();          ((zookeeper<t>)(_zookeepers[type.fullname].orderby(k => rnd.nextdouble()).first())).careforanimal(animal); ;      } } 

Comments

Popular posts from this blog

php - render data via PDO::FETCH_FUNC vs loop -

c++ - OpenCV Error: Assertion failed <scn == 3 ::scn == 4> in unknown function, -

The canvas has been tainted by cross-origin data in chrome only -