• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#中设计、使用Fluent API

C#中设计、使用Fluent API

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了fluent api,fluent使用教程,fluent6.3.26使用教程,fluent使用,fluent6.3使用教程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

我们经常使用的一些框架例如:EF,Automaper,NHibernate等都提供了非常优秀的Fluent API, 这样的API充分利用了VS的智能提示,而且写出来的代码非常整洁。我们如何在代码中也写出这种Fluent的代码呢,我这里介绍3总比较常用的模式,在这些模式上稍加改动或者修饰就可以变成实际项目中可以使用的API,当然如果没有设计API的需求,对我们理解其他框架的代码也是非常有帮助。

一、最简单且最实用的设计

这是最常见且最简单的设计,每个方法内部都返回return this; 这样整个类的所有方法都可以一连串的写完。代码也非常简单:

使用起来也非常简单:

public class CircusPerformer
 {
   public List<string> PlayedItem { get; private set; }
 
   public CircusPerformer()
   {
     PlayedItem=new List<string>();
   }
   public CircusPerformer StartShow()
   {
     //make a speech and start to show
     return this;
   }
   public CircusPerformer MonkeysPlay()
   {
     //monkeys do some show
     PlayedItem.Add("MonkeyPlay");
     return this;
   }
   public CircusPerformer ElephantsPlay()
   {
     //elephants do some show
     PlayedItem.Add("ElephantPlay");
     return this;
   }
   public CircusPerformer TogetherPlay()
   {
     //all of the animals do some show
     PlayedItem.Add("TogetherPlay");
     return this;
   }
   public void EndShow()
   {
     //finish the show
   }

</div>

调用:

[Test]
    public void All_shows_can_be_invoked_by_fluent_way()
    {
      //Arrange
      var circusPerformer = new CircusPerformer();
       
      //Act
      circusPerformer
        .MonkeysPlay()
        .ElephantsPlay()
        .StartShow()
        .TogetherPlay()
        .EndShow();
 
      //Assert
      circusPerformer.PlayedItem.Count.Should().Be(3);
      circusPerformer.PlayedItem.Contains("MonkeysPlay");
      circusPerformer.PlayedItem.Contains("ElephantsPlay");
      circusPerformer.PlayedItem.Contains("TogetherPlay");
    }
</div>

但是这样的API有个瑕疵,马戏团circusPerformer在表演时是有顺序的,首先要调用StartShow(),其次再进行各种表演,表演结束后要调用EndShow()结束表演,但是显然这样的API没法满足这样的需求,使用者可以随心所欲改变调用顺序。

如上图所示,vs将所有的方法都提示了出来。

我们知道,作为一个优秀的API,要尽量避免让使用者犯错,比如要设计private 字段,readonly 字段等都是防止使用者去修改内部数据从而导致出现意外的结果。

二、设计具有调用顺序的Fluent API

在之前的例子中,API设计者期望使用者首先调用StartShow()方法来初始化一些数据,然后进行表演,最后使用者方可调用EndShow(),实现的思路是将不同种类的功能抽象到不同的接口中或者抽象类中,方法内部不再使用return this,取而代之的是return INext;

根据这个思路,我们将StartShow(),和EndShow()方法抽象到一个类中,而将马戏团的表演抽象到一个接口中:

public abstract class Performer
 {
   public abstract ICircusPlayer CircusPlayer { get; }
   public abstract ICircusPlayer StartShow();
   public abstract void EndShow();
 }

</div>
public interface ICircusPlayer
{
  IList PlayedItem { get; }
  ICircusPlayer MonkeysPlay();
  ICircusPlayer ElephantsPlay();
  Performer TogetherPlay();
}
</div>


有了这样的分类,我们重新设计API,将StartShow()和EndShow()设计在CircusPerfomer中,将马戏团的表演项目设计在CircusPlayer中:

public class CircusPerformer:Performer
 {
   private ICircusPlayer _circusPlayer;
 
   override public ICircusPlayer CircusPlayer { get { return _circusPlayer; } }
 
   public override ICircusPlayer StartShow()
   {
     //make a speech and start to show
     _circusPlayer=new CircusPlayer(this);
     return _circusPlayer;
   }
   
   public override void EndShow()
   {
     //finish the show
   }
 }

</div>

public class CircusPlayer:ICircusPlayer
 {
   private readonly Performer _performer;
   public IList PlayedItem { get; private set; }
 
   public CircusPlayer(Performer performer)
   {
     _performer = performer;
     PlayedItem=new List();
   }
 
   public ICircusPlayer MonkeysPlay()
   {
     PlayedItem.Add("MonkeyPlay");
     //monkeys do some show
     return this;
   }
 
   public ICircusPlayer ElephantsPlay()
   {
     PlayedItem.Add("ElephantPlay");
     //elephants do some show
     return this;
   }
 
   public Performer TogetherPlay()
   {
     PlayedItem.Add("TogetherPlay");
     //all of the animals do some show
     return _performer;
   }
 }



这样的API可以满足我们的要求,在马戏团circusPerformer实例上只能调用StartShow()和EndShow()

调用完StartShow()后方可调用各种表演方法。

当然由于我们的API很简单,所以这个设计还算说得过去,如果业务很复杂,需要考虑众多的情形或者顺序我们可以进一步完善,实现的基本思想是利用装饰者模式和扩展方法,由于园子里的dax.net在很早前就发表了相关博客在C#中使用装饰器模式和扩展方法实现Fluent Interface,所以大家可以去看这篇文章的实现方案,该设计应该可以说是终极模式,实现过程也较为复杂。

三、泛型类的Fluent设计

泛型类中有个不算问题的问题,那就是泛型参数是无法省略的,当你在使用var list=new List<string>()这样的类型时,必须指定准确的类型string。相比而言泛型方法中的类型时可以省略的,编译器可以根据参数推断出参数类型,例如

var circusPerfomer = new CircusPerfomerWithGenericMethod();
      circusPerfomer.Show<Dog>(new Dog());
      circusPerfomer.Show(new Dog());
</div>


如果想省略泛型类中的类型有木有办法?答案是有,一种还算优雅的方式是引入一个非泛型的静态类,静态类中实现一个静态的泛型方法,方法最终返回一个泛型类型。这句话很绕口,我们不妨来看个一个画图板实例吧。

定义一个Drawing<TShape>类,此类可以绘出TShape类型的图案

public class Drawing<TShape> where TShape :IShape
  {
    public TShape Shape { get; private set; }
    public TShape Draw(TShape shape)
    {
      //drawing this shape
      Shape = shape;
      return shape;
    }
  }
</div>

定义一个Canvas类,此类可以画出Pig,根据传入的基本形状,调用对应的Drawing<TShape>来组合出一个Pig来

public void DrawPig(Circle head, Rectangle mouth)
   {
     _history.Clear();
     //use generic class, complier can not infer the correct type according to parameters
     Register(
       new Drawing<Circle>().Draw(head),
       new Drawing<Rectangle>().Draw(mouth)
       );
   }

</div>

这段代码本身是非常好懂的,而且这段代码也很clean。如果我们在这里想使用一下之前提到过的技巧,实现一个省略泛型类型且比较Fluent的方法我们可以这样设计:

首先这样的设计要借助于一个静态类:

public static class Drawer
 {
   public static Drawing<TShape> For<TShape>(TShape shape) where TShape:IShape
   {
     return new Drawing<TShape>();
   }
 }

</div>

 然后利用这个静态类画一个Dog

public void DrawDog(Circle head, Rectangle mouth)
   {
     _history.Clear();
     //fluent implements
     Register(
       Drawer.For(head).Draw(head),



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C#中设计、使用Fluent API

相关文章

  • 2017-05-28C#基于WebBrowser获取cookie的实现方法
  • 2017-05-28C#图像透明度调整的方法
  • 2017-05-28C#连接db2数据库的实现方法
  • 2017-05-28举例讲解C#中自动实现的属性
  • 2017-05-28基于C# 中可以new一个接口?的问题分析
  • 2017-05-28C#删除文件目录或文件的解决方法
  • 2017-05-28C#中static静态变量的用法实例
  • 2017-05-28支持多类型数据库的c#数据库模型示例
  • 2017-05-28C#实现XML文档的增删改查功能示例
  • 2017-05-28C#实现12306自动登录的方法

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 浅谈C#中的委托、事件与异步
    • C#中设置textbox限制条件的方法
    • c#的datatable转list示例
    • DevExpress实现GridControl单元格编辑验证的方法
    • .NET中的Timer类型用法详解
    • c#的params参数使用示例
    • C#使用委托的步骤浅析
    • Js中的substring,substr与C#中的Substring比较
    • C#常用目录文件操作类实例
    • c#网络唤醒功能实现

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有