stream畅的C#接口和inheritance

我将通过示例来展示一个问题。 有一个stream畅的界面的基类:

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); } } 

和一个孩子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); } } 

问题是,当你调用customer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith")不能在最后添加.WithId(123) ,因为WithLastName()方法是FluentPerson(不是FluentCustomer)。

这个问题通常如何解决?

你可以使用generics来实现这一点。

 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; } } 

现在:

 var customer = new FluentCustomer() .WithAccountNumber("123") .WithFirstName("Abc") .WithLastName("Def") .ToString(); 

尝试使用一些扩展方法。

 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); } } 

之后你可以使用像

 new FluentCustomer().WithId(22).WithFirstName("dfd").WithId(32); 

从逻辑上讲,你需要configuration从最具体(客户)到最不具体(人)的东西,否则甚至很难阅读,尽pipestream畅的界面。 在大多数情况下遵循这个规则,你不需要惹麻烦。 如果不pipe出于什么原因,你仍然需要混合它,你可以使用中等强调语句

 static class Customers { public static Customer AsCustomer(this Person person) { return (Customer)person; } } customer.WIthLastName("Bob").AsCustomer().WithId(10); 

您需要stream畅的界面,inheritance和一些generics的解决scheme…

无论如何,正如我之前所说:这是唯一的select,如果你想使用inheritance和访问也受保护的成员…

 public class GridEx<TC, T> where TC : GridEx<TC, T> { public TC Build(T type) { return (TC) this; } } public class GridExEx : GridEx<GridExEx, int> { } class Program { static void Main(string[] args) { new GridExEx().Build(1); } } 
  public 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); } } public class FluentCustomer { private string _AccountNumber = String.Empty; private string _id = String.Empty; FluentPerson objPers=new FluentPerson(); public FluentCustomer WithAccountNumber(string accountNumber) { _AccountNumber = accountNumber; return this; } public FluentCustomer WithId(string id) { _id = id; return this; } public FluentCustomer WithFirstName(string firstName) { objPers.WithFirstName(firstName); return this; } public FluentCustomer WithLastName(string lastName) { objPers.WithLastName(lastName); return this; } public override string ToString() { return objPers.ToString() + String.Format(" account number: {0}", _AccountNumber); } } 

并使用它来调用它

  var ss = new FluentCustomer().WithAccountNumber("111").WithFirstName("ram").WithLastName("v").WithId("444").ToString(); 

stream畅的界面真的是最好的调用,或者初始化器会更好吗?

  var p = new Person{ LastName = "Smith", FirstName = "John" }; var c = new Customer{ LastName = "Smith", FirstName = "John", AccountNumber = "000", ID = "123" }; 

不像一个stream畅的接口,这工作正常,没有inheritance的方法回馈基类和搞乱链。 当你inheritance一个属性时,调用者实际上不应该关心FirstName是否首先在Person或者Customer或者Object中被实现。

无论是在一条线还是多条线上,我发现它更具可读性, 而且您不必经历提供与每个属性相对应的stream畅自装饰function的麻烦。