当前位置: 首页 > 编程日记 > 正文

[.NET] 《Effective C#》快速笔记 - C# 中的动态编程

《Effective C#》快速笔记 - C# 中的动态编程

静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作。C# 是一种静态类型的语言,不过它加入了动态类型的语言特性,可以更高效地解决问题。

一、目录

  • 三十八、理解动态类型的优劣
  • 三十九、使用动态类型表达泛型类型参数的运行时类型
  • 四十、将接受匿名类型的参数声明为 dynamic
  • 四十一、用 DynamicObject 或 IDynamicMetaObjectProvider 实现数据驱动的动态类型
  • 四十二、如何使用表达式 API
  • 四十三、使用表达式将延迟绑定转换为预先绑定
  • 四十四、尽量减少在公有 API 中使用动态类型

三十八、理解动态类型的优劣

  1. C# 动态类型是为了让静态代码能够更加平滑地与其他使用动态类型的环境进行交互,而不是鼓励在一般场景中使用 dynamic 进行动态编程。

  2. 只要对象在运行时包含成员,那么即可正常使用。

  3. 若是一个操作数(包括 this)为动态类型,那么返回结果也会是动态类型。不过,最后依然要转换成静态类型,以便被其它 C# 代码所使用,以及被编译器感知。

  4. 当你需要不知道具体类型的运行时解析方法的时候,动态类型是最佳的工具。如果你能在编译期间明确类型,那么可以使用 lambda 表达式和函数式编程来解决问题。

  5. 表达式树,一种在运行时创建代码的方法(下面提供示例)。

  6. 大多数情况,可以使用 Lambda 表达式创建泛型 API,让调用者自己动态定义所需要执行的代码即可。

  7. 优先使用静态类型,静态类型比动态类型更高效,动态类型和在运行时创建表达式树都会带来性能上的影响,即便这点影响微不足道。

  8. 若你能控制程序中所有涉及的类型时,可以引入一个接口,而不是动态类型,即基于接口编程,并让所有需要支持该接口行为的类型都实现该接口。通过 C# 类型系统可以减少代码在运行时所产生的错误,编译器也能够生成更加高效的代码。

  9. 动态类型做法的效率比纯粹的静态类型下降挺大,但实现的难度却比解析表达式树要简单地挺多。

这里,我使用 3 种数字相加的方法,dynamic 动态、Func 委托以及使用表达式树进行相加的区别:

        [TestMethod]public void Test(){var result1 = AddDynamic(2, 3);Console.WriteLine((int)result1);var result2 = AddFunc(3, 4, (x, y) => x + y);Console.WriteLine(result2);var result3 = AddExpressionTree(4, 5);Console.WriteLine(result3);}/// <summary>/// Add,动态/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>private dynamic AddDynamic(dynamic a, dynamic b){return a + b;}/// <summary>/// Add,使用委托/// </summary>/// <typeparam name="T1"></typeparam>/// <typeparam name="T2"></typeparam>/// <typeparam name="TR"></typeparam>/// <param name="a"></param>/// <param name="b"></param>/// <param name="func"></param>/// <returns></returns>private TR AddFunc<T1, T2, TR>(T1 a, T2 b, Func<T1, T2, TR> func){return func(a, b);}/// <summary>/// Add,使用表达式树/// </summary>/// <typeparam name="T"></typeparam>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>private T AddExpressionTree<T>(T a, T b){ParameterExpression leftOperand = Expression.Parameter(typeof(T), "left");ParameterExpression rightOperand = Expression.Parameter(typeof(T), "right");BinaryExpression body = Expression.Add(leftOperand, rightOperand);Expression<Func<T, T, T>> adder = Expression.Lambda<Func<T, T, T>>(body, leftOperand, rightOperand);Func<T, T, T> theDelegate = adder.Compile();return theDelegate(a, b);}}

三十九、使用动态类型表达泛型类型参数的运行时类型

  1. System.Linq.Enumerable.Cast<T> 将序列中的对象转换成 T,从而使得 LINQ 可以配合 IEnumerable 进行工作。

  2. Convert<T> 要比 Cast<T> 适用性更广,但同时也会执行更多的工作。

四十、将接受匿名类型的参数声明为 dynamic

  1. 不要过度使用动态类型,因为动态调用会增加系统的额外开销,即便不大。

  2. 长远来看,具体类型更易于维护,编译器和类型系统也会为其提供更好的支持。

  3. 扩展方法不能基于动态对象定义。

四十一、用 DynamicObject 或 IDynamicMetaObjectProvider 实现数据驱动的动态类型

  1. 创建带有动态功能的类型的最简单的方法就是继承 System.Dynamic.DynamicObject。若能直接继承 DynamicObject,那么创建动态类就会比较简单。

  2. 实现 IDynamicMetaObjectProvider 就意味着需要实现方法 GetmetaObject()。

  3. 创建动态类型时首选继承,如果必须使用其他基类,可以手工实现 IDynamicMetaObjectProvider 接口,虽然所有的动态类型都会带来性能上的损失,但这种手工实现接口的方式所带来的损失往往更大一些。

这是一个实现动态类型模型的一个示例。除了需要继承 DynamicObject,还需要重写 TryGetMemebr() 和 TrySetMemebr()。

        [TestMethod]public void Test1(){dynamic propDynamic = new DynamicPropertyBag();propDynamic.Now = DateTime.Now;Console.WriteLine(propDynamic.Now);}/// <summary>/// 动态属性绑定模型/// </summary>internal class DynamicPropertyBag : DynamicObject{private readonly Dictionary<string, object> _storage = new Dictionary<string, object>();/// <summary>/// 获取属性值/// </summary>/// <param name="binder"></param>/// <param name="result"></param>/// <returns></returns>public override bool TryGetMember(GetMemberBinder binder, out object result){var key = binder.Name;if (_storage.ContainsKey(key)){result = _storage[key];return true;}result = null;return false;}/// <summary>/// 设置属性值/// </summary>/// <param name="binder"></param>/// <param name="value"></param>/// <returns></returns>public override bool TrySetMember(SetMemberBinder binder, object value){var key = binder.Name;try{if (_storage.ContainsKey(key)){_storage[key] = value;}else{_storage.Add(key, value);}return true;}catch (Exception e){Console.WriteLine(e);return false;}}

四十二、如何使用表达式 API

  1. 传统的反射 API 可以用表达式和表达式树进行更好的替代,表达式可以直接编译为委托。

  2. 接口使我们可以得到一个更为清晰、也更具可维护性的系统,反射是一个很强大的晚期绑定机制(虽然效率有所降低),.NET 框架使用它来实现 Windows 控件和 Web 控件的数据绑定。

这里提供了一个示例:

        [TestMethod]public void Test2(){var result = Call<int, string>((x) => (x * 2).ToString("D"));Console.WriteLine(result);}/// <summary>/// 调用/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="TResult"></typeparam>/// <param name="op"></param>/// <returns></returns>private TResult Call<T, TResult>(Expression<Func<T, TResult>> op){var exp = op.Body as MethodCallExpression;var result = default(TResult);if (exp == null){return result;}var methodName = exp.Method.Name;var parameters = exp.Arguments.Select(ProcessArgument);Console.WriteLine($"方法名 {methodName}");foreach (var parameter in parameters){Console.WriteLine("参数:");Console.WriteLine($"\t{parameter.Item1}:{parameter.Item2}");}return result;}/// <summary>/// 处理参数/// </summary>/// <param name="expression"></param>/// <returns></returns>private Tuple<Type, object> ProcessArgument(Expression expression){object arg = default(object);LambdaExpression l = Expression.Lambda(Expression.Convert(expression, expression.Type));Type parmType = l.ReturnType;arg = l.Compile().DynamicInvoke();return Tuple.Create(parmType, arg);}

四十三、使用表达式将延迟绑定转换为预先绑定

  1. 延迟绑定API要使用符号(symbol)信息来实现,而预先编译好的 API 则无需这些信息,表达式 API 正是二者之间的桥梁。

  2. 延迟绑定常见于 Silverlight 和 WPF 中使用的属性通知接口,通过实现 INotifyPropertyChanged 和 INotifyPropertyChanging 接口来实现属性变更的预绑定。

四十四、尽量减少在公有 API 中使用动态类型

  1. 优先使用 C# 的静态类型,并尽可能地降低动态类型的作用范围。若是想一直使用动态特性,你应该直接选用一种动态语言,而非 C#。

  2. 若要在程序中使用动态特性,请尽量不要在公有接口中使用,这样会将动态类型限制在一个单独的对象(或类型)中。

本系列

《Effective C#》快速笔记(一)- C# 语言习惯

《Effective C#》快速笔记(二)- .NET 资源托管

《Effective C#》快速笔记(三)- 使用 C# 表达设计

《Effective C#》快速笔记(四) - 使用框架

《Effective C#》快速笔记(五) - C# 中的动态编程

《Effective C#》快速笔记(六) - C# 高效编程要点补充


【博主】反骨仔

【原文】http://www.cnblogs.com/liqingwen/p/6816100.html

【GitHub】https://github.com/liqingwen2015/XMind 可以下载 XMind

【参考】《Effective C#》

 【参考】http://blog.csdn.net/w174504744/article/details/50562109

转载于:https://www.cnblogs.com/liqingwen/p/6816100.html

相关文章:

阿里云https证书apache配置

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 一&#xff1a;下载证书&#xff1b; 二&#xff1a;安装证书 文件说明&#xff1a; 1. 证书文件1534884149377.pem&#xff0c;包含两段内容&#xff0c;请不要删除任何一段内容。…

vue css 应用变量_如何使用CSS Grid和CSS变量快速为应用创建原型

vue css 应用变量CSS Grid and CSS Variables are both huge wins for front-end developers. The former makes it dead simple to create website layouts, while the latter brings the power of variables to your stylesheets.CSS Grid和CSS变量对于前端开发人员都是巨大的…

linux--memcache的安装和使用(转)

memcache是高性能&#xff0c;分布式的内存对象缓存系统&#xff0c;用于在动态应用中减少数据库负载&#xff0c;提升访问速度。据说官方所说&#xff0c;其用户包括twitter、digg、flickr等&#xff0c;都是些互联网大腕呀。目前用memcache解决互联网上的大用户读取是非常流行…

EF 调试跟踪生成的SQL语句

IQueryable query from x in appEntitieswhere x.id 10select x;var sql ((System.Data.Objects.ObjectQuery)query).ToTraceString(); 或者 EF6 &#xff1a; var sql ((System.Data.Entity.Core.Objects.ObjectQuery)query).ToTraceString(); 转载于:https://www.cnblogs…

微信小程序图片自适应宽高比例显示解决方法

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 解决方案一&#xff1a;写固定宽度&#xff0c;然后使用 image 组件中 mode 属性的 widthFix &#xff1b; 先看效果图&#xff1a; 实现代码&#xff1a; <image classmy_img mo…

初创公司面试要问什么_聘请初创公司的产品设计师时要问的问题

初创公司面试要问什么by Bohdan Kit通过Bohdan Kit 聘请初创公司的产品设计师时要问的问题 (Questions to ask when hiring a product designer for a startup) 在人群中寻找隐藏宝石的方法指南 (A how-to guide on finding hidden gems in the crowd) Finding the right pers…

Select Top在不同数据库中的使用

1. oracle数据库 SELECT * FROM TABLE1 WHERE ROWNUM<N 2. Infomix数据库 SELECT FIRST N * FROM TABLE1 3. DB2数据库 SELECT * ROW_NUMBER() OVER(ORDER BY COL1 DESC) AS ROWNUM WHERE ROWNUM<N 或者 SELECT COLUMN FROM TABLE FETCH FIRST N ROWS ONLY 4. SQL Server…

bat+sqlcmd 批量执行脚本

Hello,此BAT脚本能够帮助开发者将某目录下全部SQL脚本按文件名称依次在指定数据库中批量执行。不用忍受powershell invoke-sqlcmd 的笨重。在指执行时多一种选择。 bat文件 echo off REM ******** ******** General Batch for Starting SQL ******** ******** REM %1 is the n…

突破微信小程序五层层级限制的解决方案

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 五层的限制只是针对 navigateTo&#xff0c;redirectTo 不受此限制。 navigateTo &#xff1a;保留当前页面&#xff0c;跳转到应用内的某个页面&#xff0c;使用wx.navigateBack可以…

react-dnd-dom_我如何使用react-dnd和react-flip-move构建React游戏

react-dnd-domby Nicholas Vincent-Hill尼古拉斯文森特希尔(Nicholas Vincent-Hill) 我如何使用react-dnd和react-flip-move构建React游戏 (How I built a React game with react-dnd and react-flip-move) This is a high level overview of my implementation of a puzzle/w…

web应用程序和web网站_Web应用程序和移动应用程序的基本启动清单

web应用程序和web网站by Ben Cheng通过本诚 Web应用程序和移动应用程序的基本启动清单 (The Essential Launch Checklist for Web Apps and Mobile Apps) This is a simple launch checklist for web and mobile apps that I’ve prepared for product and project managers t…

javascript禁止修改对象

禁止扩展 Object.preventExtensions(obj);var me {name: "xiaowtz" }; console.log(Object.isExtensible(me)); //true,对象默认都是可扩展的Object.preventExtensions(me); //禁止对象扩展后&#xff0c;不可以给对象添加新的属性console.log(Object.isExtensible(…

webpack入门之简单例子跑起来

webpack入门之简单例子跑起来 webpack介绍 Webpack是当下最热门的前端资源模块化管理和打包工具&#xff0c;它可以将很多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源&#xff0c;还可以将按需加载的模块进行代码分割&#xff0c;等到实际需要的时候再异步加载。…

微信小程序 scroll-view 根据内容的高度自适应

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 1 <video autoplay src"{{videoPlayUrl}}" controls></video> <scroll-view scroll-y style"height: {{height?heightpx:auto}}"><view c…

org.hibernate.hibernate.connection.release_mode

org.hibernate.connection包的主要封装了通过JDBC来连接数据库的操作&#xff0c;用户可以以数据源的方式&#xff0c;或者通过特定数据库驱动的方式&#xff0c;甚至是自己定义连接类的方式来完成数据库的连接操作&#xff0c;包下面的代码文件并不多&#xff0c;只有5个&…

添加百度地图最简单的办法

http://map.baidu.com/?newmap1&ieutf-8&ss%26wd%3D%E4%B8%8A%E6%B5%B7%E9%9D%92%E6%B5%A6%E5%8C%BA%E5%BE%90%E9%BE%99%E8%B7%AF77%E5%8F%B7后面加上地址就好了 比方说&#xff1a;http://map.baidu.com/?newmap1&ieutf-8&ss%26wd%3D%E4%B8%8A%E6%B5%B7%E9%…

微信小程序的数字有部分会自动加粗的解决方法

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; bug图&#xff1a; 能看到&#xff0c;0和1是一个标签里面的&#xff0c;但是不统一显示 此时的代码&#xff1a; <view>2018-08-01</view> 修改后的代码&#xff1a;…

ux设计_从UX设计人员的角度来看Microsoft Build 2018

ux设计by Samuele Dassatti通过萨穆尔达萨蒂 从UX设计人员的角度来看Microsoft Build 2018 (Microsoft Build 2018 from the perspective of a UX designer) I recently attended Microsoft Build 2018 in Seattle, because one of my apps was nominated for Design Innovato…

DFS template and summary

最近一直在学习Deep Frist Search&#xff0c;也在leetcode上练习了不少题目。从最开始的懵懂&#xff0c;到现在遇到问题基本有了思路。依然清晰的记得今年2月份刚开始刷题的时做subsets的那个吃力劲&#xff0c;脑子就是转不过来到底该如何的递归&#xff0c;甚至试过使用deb…

linux gcc安装

2004年4月20日最新版本的GCC编译器3.4.0发布了。目前&#xff0c;GCC可以用来编译C/C、FORTRAN、java、OBJC、ADA等语言的程序&#xff0c;可根据需要选择安装支持的语言。GCC 3.4.0比以前版本更好地支持了C标准。本文以在Redhatlinux上安装GCC3.4.0为例&#xff0c;介绍了GCC的…

js中 let var const 的差异和使用场景

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 建议使用的优先级&#xff1a;const > let > var ES6 提出了两个新的声明变量的命令&#xff1a;let和const。其中&#xff0c;let完全可以取代var&#xff0c;因为两…

bulma.css_如何建立一个? 具有Bulma CSS的特斯拉响应页面

bulma.cssby ZAYDEK由ZAYDEK 0-60 in 1.9s&#xff1f; (0-60 in 1.9s ?) 如何建立一个&#xff1f; 具有Bulma CSS的特斯拉响应页面 (How To Build A ? Responsive Tesla Launch Page With Bulma CSS) 加速可持续网页设计的到来 (To accelerate the advent of sustainable …

hdu 5099 Comparison of Android versions 枚举题意

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid5099 卡读题&#xff0c;实际上题目中表述的题意并不完整&#xff0c;所以要认真读并且加上一些现实的“常识” 关于枚举题意&#xff0c;感觉应该三个人分别看&#xff0c;然后讨论出最有可能的题意是什么 为了…

去除按钮的样式

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 去除按钮默认点击效果&#xff1a; 在button标签里面添加属性&#xff1a; hover-class"none"&#xff1b; 为了方便大家&#xff0c;下面列出微信请求服务器常用的几种方…

移动应用程序和网页应用程序_您的移动应用程序运行缓慢的主要原因以及如何修复它...

移动应用程序和网页应用程序by Rajput Mehul通过拉杰普特梅胡尔(Rajput Mehul) 您的移动应用程序运行缓慢的主要原因以及如何修复它 (Top Reasons Why Your Mobile App is Slow and How to Fix it) At a time when technology is moving ahead at an express pace and people …

邮箱验证功能原理 语法 属性

邮箱验证功能原理 1 [已解决问题] 浏览: 3508次 很多地方都在注册账号的时候使用邮箱验证功能。注册后发送一封邮件到注册邮箱里面。然后点击 邮箱里面的链接 激活邮箱。 还有手机验证 这些的原理是 怎么样的。忘指点 .NET技术 ASP.NETyzy | 菜鸟二级 | 园豆&#xff1a;295 提…

直接通过OptionalAttribute, DefaultParameterValueAttribute定义缺省参数

转载于:https://www.cnblogs.com/liuxiaoji/p/4519266.html

微信小程序学习做动画效果

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 微信扫码学习&#xff0c;在线指导微信小程序动画效果的实现

rails 添加外键_如何在Rails后端中添加功能强大的搜索引擎

rails 添加外键by Domenico Angilletta通过多梅尼科安吉列塔(Domenico Angilletta) In my experience as a Ruby on Rails Developer, I often had to deal with adding search functionality to web applications. In fact, almost all applications I worked on at some poi…

基础总结篇之一:Activity生命周期

子曰&#xff1a;溫故而知新&#xff0c;可以為師矣。《論語》 学习技术也一样&#xff0c;对于技术文档或者经典的技术书籍来说&#xff0c;指望看一遍就完全掌握&#xff0c;那基本不大可能&#xff0c;所以我们需要经常回过头再仔细研读几遍&#xff0c;以领悟到作者的思想精…