戏精分享 C#表达式树,第一季正式完稿

前不久,我们发布了《只要十步,你就可以应用表达式树来优化动态调用》。

观众们普遍反映文章的内容太多复杂不太容易理解。

因此,我们以此为契机发布了《戏精分享 C#表达式树》系列视频。现在,第一季的视频已经正式完稿,发布到了 B 站之上。

各位可以前往以下地址来查看内容:https://www.bilibili.com/video/BV15y4y1r7pK

Newbe.ObjectVisitor 0.1.4 现已可用

Newbe.ObjectVisitor 帮助开发者可以用最简单的最高效的方式访问一个普通 class 的所有属性。从而实现:验证、映射、收集等等操作。

例如, 在你的代码中有这样一个简单的类。

var order = new OrderInfo();

你想要将这个类所有的属性和值都打印出来,那么你可以采用反射来完成:

for(var pInfo in typeof(OrderInfo).GetProperties())
{Console.Writeline($"{pInfo.Name}: {pInfo.GetValue(order)}");
}

如果你使用这个类库,则可以采用以下方式来实现一样的效果:

// call .V what is a static extension method
// you get a visitor object for order
var visitor = order.V();visitor.ForEach(context=>{var name = context.Name;var value = context.Value;Console.Writeline($"{name}: {value}");
}).Run();// you can also make it into one line
order.V().ForEach(c=> Console.Writeline($"{c.Name}: {c.Value}")).Run();// or using quick style
order.FormatToString();

那我为什么要这样做?

  • 因为这样更快!这个类库使用表达式树实现,因此它拥有比直接使用反射快上 10 倍的性能.

  • 因为这样更可读!通过这个类库你可以使用链式 API 和命名方法来创建一个委托,这样可以让你的代码实现和硬编码同样的可读效果。

  • 因为这样更具扩展性!如果使用了这个类库,你就拥有了一个简便的方法来访问一个类所有的属性。因此,你就做很多你想做的事情,比如:创建一个验证器来验证你的模型,修改一些可能包含敏感数据的属性从而避免输出到日志中,创建一个类似于 AutoMapper 的对象映射器但是拥有更好的性能,诸如此类。

我们发布了第一个版本。0.1 版本中我们完成了最基础的 ForEach API,并且实现了 FormatString 方法。

我们对初始版本进行了基准测试。得出了以下结论,详细的内容也可以前往仓库首页查看:

  1. 该类库可以实现和硬编码一样快速的性能。

  2. 该类库比直接使用反射更快。

  3. 对于非代码热点路径,即使使用非缓存方式调用也仍然在可接受范围内容。

Cache

NoCache

目前,我们还有很多计划中的 API

icon remark
✔️ it is already avaliable in latest version
???? still in plan or development and will be changed or removed
it is removed form the latest version
var o = new Yueluo();using Newbe.ObjectVisitor;//✔️ from 0.1
// V is a static extension method
var visitor = o.V();//✔️ from 0.1
// create visitor from factory method
var visitor = typeof(Yueluo).V();//✔️ from 0.1
// create and fire way.
// this is the most simple structure about this lib
// there are Name, Value, PropertyInfo, SourceObj, SourceObjType and etc in the context
o.V().ForEach((context)=>{}).Run();
o.V().ForEach((name,value)=>{}).Run();//✔️ from 0.1
// create a visitor with extend object as parameter
o.V().WithExtendObject<Yueluo, StringBuilder>().ForEach((context)=>{var _ = context.ExtendObject}).Run(new StringBuilder());
o.V().WithExtendObject<Yueluo, StringBuilder>().ForEach((name,value,stringBuilder)=>{}).Run(new StringBuilder());//✔️ from 0.1
// create and cache way. This is suggested way to use.
// cache object visitor to run it with anothor object
var cachedVisitor = deafult(Yueluo).V().ForEach((context)=>{}).Cache();
cachedVisitor.Run(new Yueluo());//✔️ from 0.1
// cache object visitor with extend object
var cachedVisitor = deafult(Yueluo).V().WithExtendObject<Yueluo, StringBuilder>().ForEach((context)=>{var _ = context.ExtendObject}).Cache();
cachedVisitor.Run(new Yueluo(), new StringBuilder());//???? you can modify value if return a new value
o.V().ForEach((context)=>context.Value.SubString(0,1)).Run();//✔️ from 0.1
// get debug info about expression now
var debugInfo = o.V().ForEach((context)=>{}).GetDebugInfo();//???? generate code in C# as a string about expression now
var code = o.V().ForEach((context)=>{}).GenerateCode();//✔️ from 0.1
// generate a lambda func
var func = o.V().ForEach((context)=>{}).GetLambda();//???? foreach properties with specified type
o.V().ForEach<string>((context)=>{}).Run();//????  using linq to filter
o.V().AsEnumerable().Where((context)=>context.Name == "YueLuo").ForEach((context)=>{}).Run();//????  suppending visiting sub object
o.V().SuppendSubObject().ForEach((context)=>{}).Run();//????  suppending visiting enumerable object
o.V().SuppendEnumerable().ForEach((context)=>{}).Run();/**✔️ from 0.1sample to join all properties to string
*/
var sb = new StringBuilder();
o.V().ForEach((context)=>{sb.Append(context.Name);sb.Append(context.Value);sb.Append(Enviroment.Newline);
}).Run();
var s = sb.ToString();//✔️ from 0.1
// quick style for above
var s = o.FormatString();//???? Deconstruct as C# 7 but more flexible
var destructor1 = Destructor<Yueluo>.Property(x=>x.Name).Property(x=>x.Age)var destructor2 = Destructor<Yueluo>.Property(x=>x.Name).Property(x=>(long)x.Age)var destructor3 = Destructor<Yueluo>.Property(x=>x.Name).Property(x=>x.NickName).Property(x=>x.Age)var (name, age) = o.V().Destruct(destructor1).Run();
var (name, ageInLong) = o.V().Destruct(destructor2).Run();
var (name, nickName, age) = o.V().Destruct(destructor3).Run();// namespace for operation with collections
using Newbe.ObjectVisitor.Collections;/**????collect properties into a dictionary
*/var dic1 = o.V().CollectAsDictionary().Run();
// quick style for above
var dic1 = o.V().ToDictionary();/**????apply value from a dictionary to object
*/
o.V().ApplyFromDictionary(dic).Run();
// quick style for above
o.V().FromDictionary(dic);// namespace for data validation
using Newbe.ObjectVisitor.Validation;// ????create rule to validation
var rule = ValidateRule<Yueluo>.GetBuilder().Property(x=>x.Name).Required().Length(2,10).Property(x=>x.Age).Range(0, int.MaxValue).Property(x=>x.Password).Validate(value=>ValidatePassword(value)).Property(x=>x.Level).Validate(value=>value + 1 >= 0).Build();o.V().Validate(rule).Run();
o.Validate(rule);// ????validate data in flunet api
// attribute-based enabled by default
o.V().Validate(v=>v.Property(x=>x.Name).Required().Length(2,10).Property(x=>x.Age).Range(0, int.MaxValue).Property(x=>x.Password).Validate(value=>ValidatePassword(value)).Property(x=>x.Level).Validate(value=>value + 1 >= 0)
).Run();// ????suppending attribute-based validation
o.V().SuppendAttributeValidation().Validate(v=>v.Property(x=>x.Name).Required().Length(2,10).Property(x=>x.Age).Range(0, int.MaxValue).Property(x=>x.Password).Validate(value=>ValidatePassword(value)).Property(x=>x.Level).Validate(value=>value + 1 >= 0)
).Run();// ????suppending sub-object validation
// validate whole object
o.V().SuppendSubObject().SuppendAttributeValidation().Validate(v=>v.Validate(x=>x.NewPassword == x.OldPassword).Validate(x=>ValidateFormDb(x)).Property(x=>x.Name).Required().Length(2,10).Property(x=>x.Age).Range(0, int.MaxValue).Property(x=>x.Age).If(x=>x.Name == "123").Range(0, int.MaxValue).Property(x=>x.Password).Validate(value=>ValidatePassword(value)).Property(x=>x.Level).Validate(value=>value + 1 >= 0)
).Run();// namespace for Task
using Newbe.ObjectVisitor.Task;// ????async way
await o.V().ForEachAsync((context)=>{}).RunAsync();// ????controlling concurrency
await o.V().ForEachAsync((context)=>{}).WhenAsync(tasks=>Task.WhenAll(tasks)).RunAsync();// namespace for Microsoft.Extensions.DependencyInjection
using Newbe.ObjectVistory.DepencyInjection;// ????inject services to the properties of this object
this.V().ForEach(context=>this.ServiceProvider.GetService(context.PropertyInfo.PorpertyType)).Run();// ????quick style for above
this.V().PropertyInject(this.ServiceProvider);

究竟是什么可以比反射还快实现动态调用?相关推荐

  1. 究竟是什么可以比反射还快实现动态调用?| Source Generators版

    前言 最近在公众号上看到一篇文章<究竟是什么可以比反射还快实现动态调用?>,它使用的是Newbe.ObjectVisitor,基于C#表达式树访问一个普通class的所有属性和对应的值,可 ...

  2. 揭秘 ClownFish 比手写代码还快的原因

    说明:本文的第一版由于反对人数较多(推荐/反对数量是:23 / 17), 我在8月20日删除了博文内容,只留下一段简单的内容. 既然分享技术也引来这么多的反对,那我就不分享了. 如果希望知道我的优化方 ...

  3. 在M1芯片上跑原生Linux:编译速度比macOS还快40%,真香警告

    Alex 发自 凹非寺 量子位 | 公众号 QbitAI 现在,M1 Mac可以顺利运行原生Linux了. 专为苹果自研芯片打造的Asahi Linux项目,Alpha版本已经释出. 在Mac采用英特 ...

  4. 比反射更快:委托 第3部分

    目录 泛型方法 静态泛型方法 实例泛型方法 事件 事件添加访问器 事件删除访问者 总结 现在是时候介绍以下成员了. 泛型方法 事件 泛型方法 以前我们没有介绍C#关于方法的非常重要的特性.如果您阅读本 ...

  5. 比反射更快:委托 第2部分

    目录 构造函数 静态方法 实例方法 总结 GitHub和Nuget包中提供了具有新功能和错误修复的代码. 现在是时候介绍以下成员了.(如想了解字段.属性等情况,可查看上一篇文章) 静态的 方法 例 方 ...

  6. 比反射更快:委托 第1部分

    目录 为什么不用反射? 委托一切 静态属性 获取访问器(get accessors) 设置访问器(set accessors) 改进 属性 改进 索引器 改进 Setters 静态字段 获取静态字段值 ...

  7. python下载哪个版本好-究竟哪个版本的Python是最快的?

    作者|Anthony Shaw 编辑|安翔 Python 3 比 Python 2 慢吗?哪个版本的 Python 3 速度最快?还有哪些措施可以提高速度?究竟哪个版本的 Python 是最快的?当然 ...

  8. ClownFish:比手写代码还快的通用数据访问层

    最近花了二个月的业余时间重写了我以前的通用数据访问层, 由于是重写,所以我给这个项目取了个新名字:ClownFish 如果需要了解ClownFish的使用方法,请点击ClownFish 使用说明 Cl ...

  9. vc的速度有c语言快吗,大家帮看看,怎么回事?Delphi竟比vc++还快

    已结贴√ 问题点数:20 回复次数:15 大家帮看看,怎么回事?Delphi竟比vc++还快 前天有一个求素数个数问题,用delphi7.0求得100000000以内素数用时21.234秒,为想更快一 ...

最新文章

  1. 一些思考,没想好标题
  2. 利用脑记录产生的合成语音
  3. 区块链 软分叉和硬分叉 简介
  4. PHP中的PHP_EOL变量
  5. 作者:刘勇,山东农业大学教授、博士生导师。
  6. 说说emit(上)基本操作
  7. 目标检测——夏侯南溪目标检测模型之数据结构
  8. 变量“componentresourcemanager”未声明或从未赋值_频繁出现在面试题中,却容易被人遗忘:变量、基本数据类型...
  9. 杭电多校HDU 6656 Kejin Player(概率DP)题解
  10. 软件测试缺陷报告分析,测试报告中的缺陷分析和测试结论应该怎么写?
  11. JAVA下载的详细教程
  12. 常用快捷键及cmd命令
  13. 华为云域名转入到阿里云的基本流程
  14. ins服务器未响应,Ins注册及登陆问题简明教程
  15. 为什么 call 比 apply 快?
  16. 【流媒体协议】图解 FLV 协议 快速入门
  17. 大比分领先!ACCV 2022 国际细粒度图像分析挑战赛冠军方案
  18. hue oozie rerun使用问题记录
  19. IE8:SCRIPT438: 对象不支持“play”属性或方法,audio.play()无法使用
  20. 错误: 找不到符号 java

热门文章

  1. E20171214-sl
  2. 我的手机 不支持箭头函数
  3. C++中数字和字符的转换
  4. [蓝桥杯] 蚂蚁感冒
  5. 2012暑假最后两次组队赛总结
  6. 页面上指定类型的控件的样式添加
  7. c#3.0关于JSON简单操作的实用帮助类(泛型实现)
  8. python多任务编程_python线程的多任务编程
  9. autocopy2u_借助AutoCopy简化Firefox中的文本复制和粘贴
  10. mysql 不要统计null_浅谈为什么Mysql数据库尽量避免NULL