我的第一个 Object Visitor

预演准备

为了顺利的进行测试,你需要确保本地已经安装了以下这些必备的软件:

  • dotnet 2.1 或者以上版本的 SDK,我们更建议直接安装 dotnet 5 SDK。下载地址:https://dotnet.microsoft.com/download
  • 安装一个趁手的 .net IDE。本演示过程将会使用 Visual Studio Code 作为基础演示 IDE。你也可以选择 Rider 或者 Visual Studio 来完成。

创建测试项目

我们需要一个测试项目来演示如何创建一个属于你的第一个 Object Visitor。

首先,确保本地已经正确安装了 dotnet 2.1 或者以上版本的 sdk,你可以运行以下命令来确认当前安装的版本:

dotnet --info

然后,随便找一个你喜欢的文件夹,运行以下命令来创建用于演示的测试控制台程序:

dotnet new console

最后,继续运行以下命令来安装最新的 Newbe.ObjectVisitor 工具包:

dotnet add package newbe.objectvisitor

这样,用于测试的项目就创建完成了。

创建一个简单的数据模型

我们使用 IDE 打开刚刚创建的项目,添加一个简单的数据模型类 OrderInfo :

public class OrderInfo
{
public int OrderId { get; set; }
public string Buyer { get; set; }
public decimal TotalPrice { get; set; }
}

实现一个拼接所有属性的逻辑

我们在 Program.cs 中添加以下代码来完成这些逻辑:

  1. new 一个 OrderInfo order
  2. 使用 StringBuilder 将 order 的所有属性名称和值拼接在一起
  3. 输出最后的 string
using System;
using System.Text;

namespace yueluo_dalao_yes
{
class Program
{
static void Main(string[] args)
{
var order = new OrderInfo
{
OrderId = 1,
Buyer = "yueluo",
TotalPrice = 62359.1478M
};
var sb = new StringBuilder();
sb.AppendFormat("{0}: {1}{2}", nameof(order.OrderId), order.OrderId, Environment.NewLine);
sb.AppendFormat("{0}: {1}{2}", nameof(order.Buyer), order.Buyer, Environment.NewLine);
sb.AppendFormat("{0}: {1}{2}", nameof(order.TotalPrice), order.TotalPrice, Environment.NewLine);
Console.WriteLine(sb.ToString());
}
}

public class OrderInfo
{
public int OrderId { get; set; }
public string Buyer { get; set; }
public decimal TotalPrice { get; set; }
}
}

我们使用以下命令来运行写好的逻辑:

dotnet run

就会得到以下这样的结果:

OrderId: 1
Buyer: yueluo
TotalPrice: 62359.1478

使用 Object Visitor 再次实现上面的逻辑

我们通过 Newbe.ObjectVisitor 来一样实现上面的逻辑:

  1. 使用 V() 扩展方法来创建一个 Object Visitor
  2. 调用 Object Visitor 的 ForEach 方法来注册 Visit 过程的行为
  3. 运行创建好的 Object Visitor
using System;
using System.Text;

namespace yueluo_dalao_yes
{
class Program
{
static void Main(string[] args)
{
var order = new OrderInfo
{
OrderId = 1,
Buyer = "yueluo",
TotalPrice = 62359.1478M
};

var sb2 = new StringBuilder();
var visitor = order.V()
.ForEach((name, value) => sb2.AppendFormat("{0}: {1}{2}", name, value, Environment.NewLine));
visitor.Run();
Console.WriteLine(sb2.ToString());
}
}

public class OrderInfo
{
public int OrderId { get; set; }
public string Buyer { get; set; }
public decimal TotalPrice { get; set; }
}
}

运行这个代码,你将会得到和上一节相同的结果。

那这么做究竟带来了什么好处?

首先,使用 Object Visitor 可以动态的适应模型类的变化,这点好处非常明显。

当 OrderInfo 中的属性增加时,“拼接部分” 的代码可以不用变化,实现动态的适配。

另外,还有一些好处是本示例没有体现的,将会在后续的文档中进行介绍:

  1. 它的运行效率很高。根据已有的基准测试,其性能表征和直接硬编码差距很小。
  2. 可以使用丰富的方式来对需要访问的属性进行多种方式过滤,例如:基于 Attribute 的过滤。
  3. 有了这种方式之后可以很轻松的扩展出基于对象属性的其他功能,例如:对象的属性验证(FluentValidation),对象的映射(AutoMapper)和对象的比较(Comparer)。

那这和直接使用反射有什么区别?

使用反射来实现以上的效果也是可以的,但相较来说,Object Visitor 的实现方式在性能方面根据优势:

  1. 根据已有的基准测试,Object Visitor 基于表达式树实现,其运行效率要比直接使用反射相关的读写方法高出许多。
  2. Object Visitor 提供了基于泛型,在一些特定的场景可以完全避免装箱拆箱所带来的开销。

你可以通过点击这里来查看使用反射和使用 object visitor 的基准测试

本篇小结

到这里,你已经初步了解了什么是 Newbe.ObjectVisitor,以及其基本的用法。

不过,这只是演示代码,展现的内容非常有限,因此,你还可以继续阅读下篇来进一步了解更多紧张刺激的特性。

发布说明

使用样例

开发文档可能随版本发生变化,查看最新的开发文档需移步 http://cn.ov.newbe.pro

番外分享

GitHub 项目地址:https://github.com/newbe36524/Newbe.ObjectVisitor

Gitee 项目地址:https://gitee.com/yks/Newbe.ObjectVisitor

相关文章
 
------ 本文结束 ------

0x01 - 我的第一个 Object Visitor的更多相关文章

  1. 在Salesforce中对某一个Object添加自定义的Button和Link

    在Salesforce中可以对某一个Object添加自定义的Button和Link,来完成特定的逻辑过程,接下来以一个简单的实例来描述整个处理流程,实现的基本功能和我另外一篇文章中描述的功能是一致的( ...

  2. 在Salesforce中可以对某一个Object的Standard Button或Link进行重写

    在Salesforce中可以对某一个Object的Standard Button或Link进行重写,来实现我们特定的逻辑过程,比如:在删除某个Object之前要判断该Object的某个Field的状态 ...

  3. 在Salesforce中对某一个Object添加 Validation Rule

    在Salesforce中可以对某一个Object添加相应的 Validation Rule 来进行一个全局的条件判断,比如满足什么样的条件的修改允许提交,不满足的要提示相应的错误信息. 要创建一个Va ...

  4. new一个Object对象占用多少内存?

    Java的自动内存管理机制省却了很多编码工作,大大地提高了Java的生产力,而且JVM的性能也越来越好,特别是G1的出现,改善了垃圾回收中stop the world的状况. 也许很多人都没有考虑过这 ...

  5. [转]new一个Object对象占用多少内存?

    我们分解下ArrayList arr = new ArrayList();等同于ArrayList arr = null;//初始化arr = new ArrayList();//实例化这两个过程.初 ...

  6. list,set等集合遍历时,不能remove集合中的元素。需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAll(list/set)操作

    list,set等集合遍历时,不能remove集合中的元素.需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAl ...

  7. php 分享一个object(stdclass)转数组的函数

    经常调用一个借口之后 返回的内容是json串,利用php函数json_decode() 解析json串之后得到的 数据类型为object(stdclass) 这是一个对象,要取其中的内容也可以 取得, ...

  8. 小程序的picker的range 是一个 Object Array (对象数组)

    小程序的picker的range 是一个 Object Array (对象数组) 数据: array: [{'id':1,'name':'Android'},{'id':2,'name':'IOS'} ...

  9. django保存一个object的时候会发出信号

    当django保存一个object的时候会发出一系列的signals,可以通过对这些signals注册listener,从而相应的signal发出时执行一定的代码. from django.core. ...

  10. 好用的一个object c 宏

    好用的一个object c 宏 from https://github.com/justzt/ios-helper/blob/master/Macro.h // // Macro.h // Photo ...

随机推荐

  1. MOS管选型

    MOS管基本参数 MOS管(Metal-Oxide-Semiconductor Field-Effect Transistor, MOSFET)作为开关元件的应用非常广泛,其开关特性与三极管相比有所不 ...

  2. 普通人如何靠 AI 副业,1 个月实现月薪 3 万 +

    在物价飞涨.经济低迷的今天,仅靠死工资,却有着不固定的开销?房贷.车贷.孩子的教育费用-- 望着日益增长的开销,你是否也在夜深人静时,为钱包的羞涩而发愁?无数次幻想过拥有一份高收入的副业,却始终在迷茫 ...

  3. 记一次 Mybatis 一级缓存清理无效引起的源码走读

    今天对象在学习 Mybatis 时发现 org.apache.ibatis.session.SqlSession 对象的 clearCache() 方法并不能清理一级缓存, 同一 session 下相 ...

  4. QT5笔记: 25. 非模态的自定义对话框

    窗口对象为QDialog 显示方法为 show(); locateCell->show(); 可以通过public方法或者信号槽机制获取非模态窗口的信息 例子:非模态窗口,为主窗口数据输入吧 v ...

  5. Sqoop - 使用场景

    Oracle >> HDFS sqoop import --connect jdbc:oracle:thin:@<oracle_host>:<oracle_port> ...

  6. Markdown 编写技巧汇总(二)

    继续上篇汇总 附-上篇汇总,接着做更加高级一点的应用技巧. [1]列表与引言嵌套 两者嵌套,如: > 我是一行文本 > 1. 文本1 > 2. 文本2 > 1. 文本 > ...

  7. 机器学习 | 强化学习(2) | 动态规划求解(Planning by Dynamic Programming)

    动态规划求解(Planning by Dynamic Programming) 动态规划概论 动态(Dynamic):序列性又或是时序性的问题部分 规划(Programming):最优化一个程序(Pr ...

  8. 【C#语法糖 Lambda】2 - 表达式树与LINQ

    一.声明 曾经遇到一个这样的场景: GetEntities(a => a.OrderKindCodeId == 16 && a.IsDeleted, this.DefaultCo ...

  9. win10/11 禁用移动热点,无法启用

    将网络重制即可

  10. DVWA靶场实战(八)——SQL Injection(Blind)

    DVWA靶场实战(八) 八.SQL Injection(Blind): 1.漏洞原理: SQL Injection(Blind)全称为SQL注入之盲注,其实与正常的SQL大同小异,区别在于一般的注入攻 ...