‘TThis’ generici per lezioni fluenti

Sto costruendo un’interfaccia fluente in cui ho una class base che contiene la maggior parte della logica fluente e una class derivata che aggiunge un comportamento specializzato. Il problema che sto affrontando è il tipo di ritorno dei metodi fluenti nella class base quando chiamato da un’istanza del tipo derivato. Dopo aver richiamato un metodo della class base, restano disponibili solo i metodi della class base per ulteriori invocazioni fluenti.

Cambiare l’ordine in cui i metodi sono invocati lo aiuterà a compilare, ma lo renderà meno leggibile, il che è il punto di riferimento per interfacce fluenti. C’è un modo per definire un tipo di “Questo” tipo per la class base in modo che tutti i metodi restituiscano lo stesso tipo.

Esempio

public class Field { public Field Name( string name ) { _name = name; return this; } } public SpecialField : Field { public SpecialField Special(){ return this; } } // !!! Arrgh. Special is not a member of the Field class. var specialField = new SpecialField() .Name( "bing" ) .Special(); 

Soluzione rotta

Ho provato a risolverlo facendo qualcosa di simile al seguente, ma non è valido C # 🙁 ma almeno esprime come mi piacerebbe codificare l’interfaccia.

 public class Field : TThis where TThis : Field { public TThis Name( string name ){...} } public SpecialField : Field<T,SpecialField> { public TThis Special(){ return this; } } 

Dopo aver esplorato alcune altre API fluenti, ho trovato come farlo. Non è così pulito, ma funziona bene. Fondamentalmente si introduce una class di base intermedia per ogni tipo derivato che si desidera utilizzare e si passa il tipo “TThis” all’attuazione effettiva.

Campione

 public class FieldBase where TThis : FieldBase { private string _name; public TThis Name( string name ) { _name = name; return (TThis)this; } } public class Field : FieldBase>{} public class SpecialFieldBase : FieldBase where TThis : SpecialFieldBase { public TThis Special(){ return (TThis)this; } } public class SpecialField : SpecialFieldBase>{} // Yeah it works! var specialField = new SpecialField() .Name( "bing" ) .Special();