Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent interfaces and inheritance in C#

I'll show a problem by example. There is a base class with fluent interface:

class FluentPerson {     private string _FirstName = String.Empty;     private string _LastName = String.Empty;      public FluentPerson WithFirstName(string firstName)     {         _FirstName = firstName;         return this;     }      public FluentPerson WithLastName(string lastName)     {         _LastName = lastName;         return this;     }      public override string ToString()     {         return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);     } } 

and a child class:

class FluentCustomer : FluentPerson {     private long _Id;      private string _AccountNumber = String.Empty;      public FluentCustomer WithAccountNumber(string accountNumber)     {         _AccountNumber = accountNumber;         return this;     }     public FluentCustomer WithId(long id)     {         _Id = id;         return this;     }      public override string ToString()     {         return base.ToString() + String.Format(" account number: {0} id: {1}", _AccountNumber, _Id);     } } 

The problem is that when you call customer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith") you can't add .WithId(123) in the end because return type of the WithLastName() method is FluentPerson (not FluentCustomer).

How this problem usually solved?

like image 470
bniwredyc Avatar asked Feb 17 '10 06:02

bniwredyc


2 Answers

Try to use some Extension methods.

static class FluentManager {     public static T WithFirstName<T>(this T person, string firstName) where T : FluentPerson     {         person.FirstName = firstName;         return person;     }      public static T WithId<T>(this T customer, long id) where T : FluentCustomer     {         customer.ID = id;         return customer;     } }  class FluentPerson {     public string FirstName { private get; set; }     public string LastName { private get; set; }      public override string ToString()     {         return string.Format("First name: {0} last name: {1}", FirstName, LastName);     } }  class FluentCustomer : FluentPerson {     public long ID { private get; set; }     public long AccountNumber { private get; set; }      public override string ToString()     {         return base.ToString() + string.Format(" account number: {0} id: {1}", AccountNumber, ID);     } } 

after you can use like

new FluentCustomer().WithId(22).WithFirstName("dfd").WithId(32); 
like image 100
Steck Avatar answered Oct 20 '22 14:10

Steck


You can use generics to achieve that.

public class FluentPerson<T>     where T : FluentPerson<T> {     public T WithFirstName(string firstName)     {         // ...         return (T)this;     }      public T WithLastName(string lastName)     {         // ...         return (T)this;     } }  public class FluentCustomer : FluentPerson<FluentCustomer> {     public FluentCustomer WithAccountNumber(string accountNumber)     {         // ...         return this;     } } 

And now:

var customer = new FluentCustomer()   .WithAccountNumber("123")   .WithFirstName("Abc")   .WithLastName("Def")   .ToString(); 
like image 37
Yann Trevin Avatar answered Oct 20 '22 15:10

Yann Trevin