首页 > 其他分享 >Clay: 创建和使用深层次对象图

Clay: 创建和使用深层次对象图

时间:2022-10-24 13:33:12浏览次数:72  
标签:FirstName person 对象 创建 LastName 深层次 Clay New

Clay 是 CodePlex 上的一个开源项目,帮助我们创建轻松创建对象,就 JavaScript 或其它动态语言一样简单。Clay 项目的网址是 http://clay.codeplex.com,Clay 目前主要应用于 Orchard 项目

Clay 是 CodePlex 上的一个开源项目,帮助我们创建轻松创建对象,就 JavaScript 或其它动态语言一样简单。Clay 项目的网址是 ​​http://clay.codeplex.com​​​,Clay 目前主要应用于 ​​Orchard​​ 项目。以下2篇文章解释了Clay的背景:

​Clay: malleable C# dynamic objects – part 1: why we need it​

​Clay: malleable C# dynamic objects – part 2​

以下内容来自上述2篇的简要摘录:

Orchard需要建立一种合适的数据结构用于在Orchard中承载视图模型(view model)——由许多不同的实体毫无约束地构建而成的时候,很快就变得非常明显必须要用一种动态结构。

我们需要的是一分层结构:一个页面可能包涵一个博客文章列表和一些微件(widgets),而每篇博客文章是由许多部件组成的,比如评论,而评论又包涵作者,作者又包涵头像、等级等等。

这就带出了第二个需求:多个实体必须在互不知道对方的情况下共同构建那个对象图(视图模型)。我们预先并不知道这个对象图的形状,且对象图的每个节点都很容易受到后来扩展节点的影响。

现在的问题是使用C#的静态类型来解决这些需求是非常不爽的。可以使用类似XML DOM API 的 ChildNodes 和 Attributes 集合 以及 NodeName and Value properties 的方式,而且这确实能够解决问题。但是 绝大多数人都会同意长期以来这种形式的API都是使开发人员痛不欲生的重要原因,因此,除非用枪指着我们的头,否则我们都不想使用这种形式。

这种形式的API之所以极其令人厌烦,最主要的原因是它首先让你获取到元数据,而把获取实际数据推到第二步API,比如Value。

现在应该比较清楚C# 中的 XML APIs之所以不爽,是因为静态语言不喜欢不可预知的东西,而想在编译时就知道对象的一切细节。XML APIs 接受预先知道的(节点拥有元数据是固化在结构里的),而把未知的东西推给属性。

换一种说法,元数据应该是对象的一个属性,而最终你得到的真正对象却是元数据结构的一个属性。

C# 4.0 提供了一个非常好的关键词适合各种各样的情况使用,它就是 ​​dynamic​​,

ExpandoObject 实际上是通过一种令人惊讶方式实现的,这使得它非常高效。提示:不是通过字典。又提示:它是一个非常好的东西。

但是,依照API 可用性原则,它不够大胆,尤其是在构建深层次动态对象图方面它并没有给我们多少帮助。它的行为也比较固定且不能被扩展。

另一方面,Clay 是高度可扩展的,且专注于深层次对象图的创建和使用。

通过 Clay 你可以做的第一件事情就是创建一个简单的对象并在它上面设置属性。在此之前,我们将首先实例化一个给我们提供 语法 语义糖衣的工厂。我希望我们能够跳过这一步而使用一些类似静态API的方式(译注:静态工厂方法),但是我们不能。好了,正如你将看到的只需很小的代价:

​​dynamic New = ​​​​new​​​ ​​ClayFactory();​​

现在这个“New”对象将帮助我们创建新的 Clay 对象,正如它的名字所暗示一样(虽然这个名字只是一个惯例而已)。

以下是一些简单且没有多少新奇的东西:

​​var person = New.Person();​​
​​person.FirstName = ​​​​"Louis"​​​​;​​
​​person.LastName = ​​​​"Dejardin"​​​​;​​

这些你都能通过 ExpandoObject 来完成的,但是这里比较有趣的地方是它有多种实现形式,且开启了发掘潜能之窗。

例如,在 Clay 中,索引语法与属性访问器是相等的,就像 JavaScript 一样。当你在写代码通过名字去访问一个属性,而这个属性的名字在编译时刻又是未知的时候,这就非常有用了:

​​var person = New.Person();​​
​​person[​​​​"FirstName"​​​​] = ​​​​"Louis"​​​​;​​
​​person[​​​​"LastName"​​​​] = ​​​​"Dejardin"​​​​;​​

但还不止于此,你还可以将属性作为链式设置器来使用,像 jQuery那样:

​​var person = New.Person()​​
​​.FirstName(​​​​"Louis"​​​​)​​
​​.LastName(​​​​"Dejardin"​​​​);​​

或者,如果你喜欢,你还可以传入一个匿名对象:

​​var person = New.Person(​​​​new​​​ ​​{​​
​​FirstName = ​​​​"Louis"​​​​,​​
​​LastName = ​​​​"Dejardin"​​
​​});​​

更加好的是,Clay 还能理解命名参数,我们可以这样写:

​​var person = New.Person(​​
​​FirstName: ​​​​"Louis"​​​​,​​
​​LastName: ​​​​"Dejardin"​​
​​);​​

总之,你可以使用很多种方式来设置属性和初始化 Clay 对象。

正如你所料,获取属性值也有多种方式且它们都是相等效果的:

​​person.FirstName​​
​​person[​​​​"FirstName"​​​​]​​
​​person.FirstName()​​

你也可以创建 JavaScript-style 数组:

​​var people = New.Array(​​
​​New.Person().FirstName(​​​​"Louis"​​​​).LastName(​​​​"Dejardin"​​​​),​​
​​New.Person().FirstName(​​​​"Bertrand"​​​​).LastName(​​​​"Le Roy"​​​​)​​
​​);​​

这种方式创建的数组也是一个完整的 Clay 对象,这意味着你可以在运行时对它添加属性。

然后,如果你想知道数组里的总项数,或者获取数组第一项的 FirstName 属性值,你可以这样:

​​people.Count​​
​​people[0].FirstName​​

当你想在一个已经存在的 Clay 对象上创建一个数组属性,这也非常容易:

​​person.Aliases(​​​​"bleroy"​​​​, ​​​​"BoudinFatal"​​​​);​​

如果有多于一个参数被传入,Clay 就会认为你正在初始化的这个属性是数组。但是如果只有0或1个参数,你只虽显式地传入一个数组 (CLR or Clay):

​​person.Aliases(​​​​new​​​​[] {​​​​"Lou"​​​​});​​

相比 CLR 数组,Clay 数组能动态增长:

​​person.Aliases.Add(​​​​"loudej"​​​​);​​

而且,它们也能够响应一些方法调用,如 AddRange, Insert, Remove, RemoveAt, Contains, IndexOf, or CopyTo 。

综合起来,我们就可以通过一种非常简洁而又富有表现力的语法来创建一个相当复杂的对象图:

​​var directory = New.Array(​​
​​New.Person(​​
​​FirstName: ​​​​"Louis"​​​​,​​
​​LastName: ​​​​"Dejardin"​​​​,​​
​​Aliases: ​​​​new​​​​[] { ​​​​"Lou"​​​ ​​}​​
​​),​​
​​New.Person(​​
​​FirstName: ​​​​"Bertrand"​​​​,​​
​​LastName: ​​​​"Le Roy"​​
​​).Aliases(​​​​"bleroy"​​​​, ​​​​"boudin"​​​​),​​
​​New.Person(​​
​​FirstName: ​​​​"Renaud"​​​​,​​
​​LastName: ​​​​"Paquay"​​
​​).Aliases(​​​​"Your Scruminess"​​​​, ​​​​"Chef"​​​​)​​
​​).Name(​​​​"Some Orchard folks"​​​​);​​

最后一点我想说明的是,Louis 第一次展示它给我看的时候,我觉得真的非常优雅和惊讶。

想像一下你有一个CLR接口需要实现,例如:

​​public​​​ ​​interface​​​ ​​IPerson {​​
​​string​​​ ​​FirstName { ​​​​get​​​​; ​​​​set​​​​; }​​
​​string​​​ ​​LastName { ​​​​get​​​​; ​​​​set​​​​; }​​
​​}​​

但是你想使用一个 Clay 对象,比如在上面定义的数组 persons 中一个元素。是的,你可以这样:

​​IPerson lou = people[0];​​
​​var fullName = lou.FirstName + ​​​​" "​​​ ​​+ lou.LastName;​​

这里最特别的是 lou 是一个非常合法的静态类型 CLR 变量,你将获得全部智能感知和编译时检查。虽然我们从未写过实现这个接口的具体类型,但它就是一个实现了 IPerson 的对象。

能够实现如此不可思议的功能,是因为 Clay 重写了转换操作符,并为这个接口创建了一个动态代理(使用 ​​Castle​​),这个动态代理再委托成员调用给 Clay 对象。

因此,那是一个真正 CLR 类型,但它是在运行时被生成的。

那就是使你能够写以下代码的:

​​foreach​​​​(var person ​​​​in​​​ ​​directory) {​​
​​Trace.Write(person.FirstName);​​
​​}​​

这里发生了事情是: “directory” Clay 数组被转换成一个 IEnumerable,而所有相应的方法都通过 Clay 动态数组对象实现。

相关文章:

​借助 Clay 编写 不可思议 的 c# 代码​

​http://weblogs.asp.net/bleroy/archive/tags/Clay/default.aspx​



标签:FirstName,person,对象,创建,LastName,深层次,Clay,New
From: https://blog.51cto.com/shanyou/5789510

相关文章

  • vue create xxx创建项目过程中报错的解决方法
    vuecreatexxx创建项目过程中报错的解决方法​​报错图例​​​​解决办法​​报错图例解决办法首先检查电脑里是否安装node.js检查方法:命令行输入node-v还要再输入一个......
  • npm -v报警告的解决方法(此警告不处理的话后续在用vue脚手架vue create xxx创建vue项
    npm-v报警告的解决方法​​警告图例​​​​第一条警告​​​​npmWARNconfigglobal'--global','--local'aredeprecated.Use`--location=global'instead.​​​......
  • 创建 个人公众号
    1.搜索微信公众平台......
  • vue创建项目的命令
    一.首先下载node环境二.全局安装vue-cli   cnpmi-g@vue/cli    这里一定要注意是vue/cli,而不是vue-cli三.新建文件夹,打开cmd命令  1.vuecreate......
  • 【XML】Java创建XML文档
    packageexample01;importorg.w3c.dom.Document;importorg.w3c.dom.Element;importjavax.xml.parsers.DocumentBuilder;importjavax.xml.parsers.DocumentBuilde......
  • 创建git远程仓库并与本地库连接
    1.首先本地库要创建一个秘钥,用于本地库和远程库之间的连接在git面板里面使用ssh-keygen,然后按几下回车,文件默认存在c盘用户目录下的.ssh目录里面  2.打开.ssh目......
  • VSCode创建Vue项目
    一、配置环境1.安装VSCode官网下载https://code.visualstudio.com/下载VSCode,按照步骤安装。2.安装node.js(1)官网https://nodejs.org/en/下载node.js,按照步骤安装即......
  • 2.8 创建文件夹 os.mkdir os.makedirs
    #创建单层文件夹os.mkdir(新文件夹名称)#创建多层文件夹os.makedirs(新文件夹名称)--------------------------------------------------------------------------------......
  • 如何用命令行语句在mysql创建库
    mysql三条创建语句创建库createdatabasediarydefaultcharsetutf8mb4;创建用户createuserdiary@localhostidentifiedby'diary';或createuser'four'@'%'iden......
  • 获取构造器和创建对象
    packagecom.liu.test03;/***@author:liu*日期:14:27:02*描述:IntelliJIDEA*版本:1.0*///子类@MyAnnotation("abc")publicclassStudentextends......