C# 使用Fluent API 创建自己的DSL(推荐)

作者:寻找无名的特质 时间:2022-03-30 23:36:48 

DSL的作用是解决领域专家与软件开发人员之间的沟通问题。听起来很唬人,其实不是什么高深的东西,我们可以使用Fluent API 创建自己的DSL

DSL(Domain Specified Language)领域专用语言是描述特定领域问题的语言,听起来很唬人,其实不是什么高深的东西。看一下下面的代码:


using FlunetApiDemo;

var 张三 = "张三"
               .是学生()
               .身高(1.62M)
               .体重(48M);

Console.WriteLine(张三.BMI());
Console.WriteLine(张三.BMI状态());

这段代码根据学生的身高体重,计算BMI并判断状态(偏瘦、正常、超重还是肥胖),看到这里,各位同学可能已经发现问题了:学生有小学生、中学生和大学生,难道计算算法一样?男生女生的计算算法也一样?在这个问题中,各位都是领域专家,从我写的描述特定问题的代码中发现了问题,我需要对代码进行修改,增加年龄和性别因素。

从上面的例子可以看到DSL的作用:是解决领域专家与软件开发人员之间的沟通问题。领域专家通常不懂得编程,无法判断开发人员写的代码是否符合领域的要求,只能是等到软件编写完成,从软件运行表现出来的功能进行判断,而这时成本已经发生了,几个来回下来,进度超时,成本超支。DSL使用领域相关的术语编写,领域专家可以理解,而语言本身基于某种宿主语言,比如C#,可以编译运行,容易验证。所以恰当的DSL可以打通领域专家和开发人员之间的障碍,使软件的业务核心部分开发可靠并有效率。“可以执行”是DSL与需求阶段使用的伪语言或者带图示的自然语言最大的不同。在需求描述的时候,经常使用各种图示或者伪语言对业务进行描述,伪语言一般是一种类似的结构化语言,这种貌似语言的东西往往是很有害的,因为只是大概描述了过程,很多实现细节被忽略或者隐藏了。由于不是严格的编程语言,无法生成可执行的代码,所以也就无法验证对错。

结合上面的例子,我们看一下如何使用Fluent Api创建自己的DSL。其使用的技术实质上是实现现有类型的扩展,这需要我们1)声明一个static类,2)在类中使用static函数,3)使用this关键字修饰需要扩展的类型。上面的"张三".是学生(),“是学生”是字符串类型的一个扩展,返回的是自己定义的Student类型,这段代码如下:


namespace FlunetApiDemo
{
   public static class FluentExt
   {
       public static Student 是学生(this string  name)
       {
           return new Student { Name = name };
       }

public static Student 身高(this Student student,decimal height)
       {
           student.Height = height;
           return student;
       }

public static Student 体重(this Student student, decimal weight)
       {
           student.Weight = weight;
           return student;
       }

public static decimal BMI(this Student student)
       {
           return student.Weight / student.Height / student.Height;
       }

public static string BMI状态(this Student student)
       {
           var bmi=student.BMI();
           if (bmi > 24) return "肥胖";
           if (bmi > 21) return "超重";
           if (bmi < 15) return "偏瘦";
           return "正常";
       }
   }
}

在Student类中只定义关键属性:


namespace FlunetApiDemo
{
   public  class Student
   {
       public string Name { get; set; }=string.Empty;

public decimal Height { get; set; }

public decimal Weight { get; set; }
       public override string ToString()
       {
           return Name;
       }
   }
}

怎么样,挺简单的吧。完整的代码上传到github: https://github.com/zhenl/FlunetApiDemo

最后的问题是代码中的中文问题,我的原则是怎么方便怎么来,通常我们编写程序时不主张使用中文作为变量或者方法名称,尽管现代编程语言的编译器很多已经不限于只支持ASCII码,但我们仍然无法确保在某些情况下不出现问题(比如如果将中文命名的方法映射为Web Api接口,不支持中文的客户端可能无法调用这个Api)。然而作为领域特定语言的DSL就不用有这个限制,DSL的主要目的就是沟通,如果必须用英文或者汉语拼音进行编写,效果就会大打折扣,更不用说很多领域都是中文为主的,这里不展开说了,举几个例子,“唐诗”、“宋词”、“元曲”估计翻成英语领域专家和程序员都看不懂。

来源:https://www.cnblogs.com/zhenl/p/15725290.html

标签:C#,Fluent,API,DSL
0
投稿

猜你喜欢

  • C#通过正则表达式实现提取网页中的图片

    2022-03-30 05:03:03
  • 详解java 中Spring jsonp 跨域请求的实例

    2023-11-19 02:48:18
  • java生成图片验证码示例程序

    2023-09-13 10:17:57
  • java编程实现优先队列的二叉堆代码分享

    2022-11-13 15:32:13
  • Java main 方法面试题的详细整理

    2023-11-24 23:53:30
  • Java 线程的优先级(setPriority)案例详解

    2023-11-12 23:46:39
  • java poi导入纯数字等格式问题及解决

    2023-04-14 08:50:30
  • java Springboot实现多文件上传功能

    2023-11-09 04:31:32
  • spring MVC实践需要注意的地方

    2023-02-07 00:33:07
  • 详解Java Proxy动态 代理机制

    2023-07-24 21:01:58
  • Java如何实现http接口参数和返回值加密

    2023-08-23 12:28:37
  • Java logback日志的简单使用

    2023-07-15 01:32:33
  • 一文带你了解RabbitMQ消息转换器

    2023-11-15 23:22:28
  • Spring Utils工具类常用方法实例

    2023-05-01 05:37:37
  • add方法理解ArrayList的扩容机制

    2023-11-24 02:16:28
  • Java进程cpu占用过高问题解决

    2021-08-09 00:16:59
  • 解决运行jar包出错:ClassNotFoundException问题

    2021-09-09 04:58:41
  • SpringBoot整合SpringTask实现定时任务的流程

    2022-03-28 22:24:40
  • flutter ExpansionTile 层级菜单的实现

    2023-06-15 16:04:01
  • Netty序列化深入理解与使用

    2023-05-24 20:13:07
  • asp之家 软件编程 m.aspxhome.com