c# - Extension methods and type inference -


i'm trying make fluent interface lots of generics , descriptors extend base descriptors. i've put in github repo because pasting of code here make unreadable.

after having read eric lippert's post type constraints (http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx) , reading no type inference generic extension method understood subject little bit better, still got questions.

suppose have classes allow fluent calls:

var giraffe = new giraffe(); new zookeeper<giraffe>()     .name("jaap")     .feedanimal(giraffe);  var reptile = new reptile(); new experiencedzookeeper<reptile>()     .name("martijn")     .feedanimal(reptile)     .cureanimal(reptile); 

the classes this:

public class zookeeper<t>     t : animal {     internal string name;     internal list<t> animalsfed = new list<t>();      // method needs fluent     public zookeeper<t> name(string name)     {         this.name = name;         return this;     }      // method needs fluent     public zookeeper<t> feedanimal(t animal)     {         animalsfed.add(animal);         return this;     } }  public class experiencedzookeeper<t> : zookeeper<t>     t : animal {     internal list<t> animalscured = new list<t>();      // method needs fluent     // must new in order able call cureanimal after     public new experiencedzookeeper<t> name(string name)     {         base.name(name);         return this;     }      // method needs fluent     // must new in order able call cureanimal after     public new experiencedzookeeper<t> feedanimal(t animal)     {         base.feedanimal(animal);         return this;     }      // method needs fluent     public experiencedzookeeper<t> cureanimal(t animal)     {         animalscured.add(animal);         return this;     } } 

i tried rid of 'new' methods in experiencedzookeeper hiding implementation of zookeeper. difference new methods in experiencedzookeeper return correct type. afaik there no way without new methods.

another approach tried take move 'setters' extension methods. works .name() method, introduces zookeeperbase contains internal field:

public abstract class zookeeperbase {     internal string name;  }  public class zookeeper<t> : zookeeperbase     t : animal {     internal list<t> animalsfed = new list<t>();       // method needs fluent     public zookeeper<t> feedanimal(t animal)     {         animalsfed.add(animal);         return this;     } }  public static class zookeeperextensions {      // method needs fluent     public static tzookeeper name<tzookeeper>(this tzookeeper zookeeper, string name)         tzookeeper : zookeeperbase     {         zookeeper.name = name;         return zookeeper;     } } 

but exact approach doesn't work feedanimal(t animal), needs type parameter :

// method needs fluent public static tzookeeper feedanimal<tzookeeper, t>(this tzookeeper zookeeper, t animal)     tzookeeper : zookeeper<t>     t : animal {     zookeeper.animalsfed.add(animal);     return zookeeper; } 

this still ok , works , can still call fluently:

new experiencedzookeeper<reptile>()     .name("martijn")     .feedanimal(reptile)     .cureanimal(reptile); 

the real problems start when try make following method fluent:

public static tzookeeper favorite<tzookeeper, t>(this tzookeeper zookeeper, func<t, bool> animalselector)     tzookeeper : zookeeper<t>     t : animal {     zookeeper.favoriteanimal = zookeeper.animalsfed.firstordefault(animalselector);     return zookeeper; } 

you cannot call favorite this:

new experiencedzookeeper<reptile>()   .name("eric")   .feedanimal(reptile)   .feedanimal(new reptile())   .favorite(r => r == reptile) 

because result in same problem no type inference generic extension method, however, case more complicated, because have type parameter tzookkeeper describes t need. eric lipperts blog post, type constraints not part of signature:

the type arguments method 'testtypeinference5.zookeeperextensions.favorite<tzookeeper,t>(tzookeeper, system.func<t,bool>)' cannot inferred usage. try specifying type arguments explicitly. 

for full code, please refer https://github.com/q42jaap/testtypeinference readme in repo explains real life problem tried solve.

so question is, there way of creating fluent method style without adding every method of zookeeper every subclass of zookeeper new hiding method of zookeeper itself?

one possibility create base class each level , empty handler class deriving it:

base classes:

public abstract class zookeeperbase<tzookeeper, tanimal>     tzookeeper : zookeeperbase<tzookeeper, tanimal>     tanimal : animal {     private string name;     private list<tanimal> animalsfed = new list<tanimal>();     private tanimal favoriteanimal;      public tzookeeper name(string name)     {         this.name = name;         return (tzookeeper)this;     }      public tzookeeper feedanimal(tanimal animal)     {         animalsfed.add(animal);         return (tzookeeper)this;     }      public tzookeeper favorite(func<tanimal, bool> animalselector)     {         favoriteanimal = animalsfed.firstordefault(animalselector);         return (tzookeeper)this;     } }  public abstract class experiencedzookeeperbase<tzookeeper, tanimal>     : zookeeperbase<tzookeeper, tanimal>     tzookeeper : experiencedzookeeperbase<tzookeeper, tanimal>     tanimal : animal {     private list<tanimal> animalscured = new list<tanimal>();      public tzookeeper cureanimal(tanimal animal)     {         animalscured.add(animal);         return (tzookeeper)this;     } } 

handler classes:

public class zookeeper<t> : zookeeperbase<zookeeper<t>, t>     t : animal { }  public class experiencedzookeeper<t>     : experiencedzookeeperbase<experiencedzookeeper<t>, t>     t : animal { } 

usage showed in question.


Comments

Popular posts from this blog

java - Jmockit String final length method mocking Issue -

asp.net - Razor Page Hosted on IIS 6 Fails Every Morning -

c++ - wxwidget compiling on windows command prompt -