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

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

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的主要目的就是沟通,如果必须用英文或者汉语拼音进行编写,效果就会大打折扣,更不用说很多领域都是中文为主的,这里不展开说了,举几个例子,“唐诗”、“宋词”、“元曲”估计翻成英语领域专家和程序员都看不懂。

到此这篇关于C# 使用Fluent API 创建自己的DSL的文章就介绍到这了,更多相关C#  Fluent API内容请搜索云海天教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持云海天教程!