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

目录

  • 二十一、限制类型的可见性
  • 二十二、通过定义并实现接口替代继承
  • 二十三、理解接口方法和虚方法的区别
  • 二十四、用委托实现回调
  • 二十五、用事件模式实现通知
  • 二十六、避免返回对内部类对象的引用
  • 二十七、让类型支持序列化
  • 二十八、提供组粒度的因特网服务 API
  • 二十九、支持泛型协变和逆变

二十一、限制类型的可见性

  1.在保证类型可以完成工作的前提下,应该尽可能地给类型分配最小的可见性。

  2.我们经常下意识的创建公有类型。可见性越低,以后升级或更改时所需要的变化就越小,因为能访问你功能模块的代码越少。

  3.创建内部类是一种常被忽略限制类型作用域的做法,我们经常习惯不假思索地创建公有类。你应该仔细思考这个一个类型的作用范围,即它是将被所有的客户使用,还是仅用在这个程序集的内部。

  4.更少的公有类型可以减少单元测试的数量。

  5.以公有形式暴露给外界的类和接口将成为你的组件的契约。接口越冗余,日后的修改就越受限。暴露的公有类型越少,以后更新扩展的时候周旋的余地就会越大。

二十二、通过定义并实现接口替代继承

  1.抽象基类为类的继承体系提供了一个共用的祖先,接口描述了一组原子性的功能。接口是一种契约,抽象基类则为一组相关的类型提供了一个共用的抽象。基类描述了对象是什么,接口描述了对象如何表现它的行为。

  2.我们可以将可重用的行为提取出来,定义在接口中。由于不相关的类型均可以实现一个接口,这表示代码的重用率将大大增加。

  3.如果向基类中添加一个方法,所有派生类都将自动包含该方法。也就是说,随着时间的推移,仍可以有效扩展多个类型功能的途径。通过向基类添加并实现某种功能,所有的派生类都将立即拥有该功能。而向接口中添加一个成员,会破坏所有实现该接口的类。因为这些类不包含新方法,每一个实现都需要进行更新,然后重新编译。

  4.在抽象基类和接口之间做选择,实际上就表示了对日后可能发生变化的不同处理态度。接口是固定的:我们将一组功能封装在一个接口,作为其他类型的契约。而基类则可以在日后扩展,这些扩展也会成为每个派生类的一部分。

  5.也可以使用扩展方法进行扩展。

    public static class Extendsions
{
public static void ForAll<T>(this IEnumerable<T> sequence, Action<T> action)
{
foreach (var item in sequence)
{
action(item);
}
}
}

  方法调用:

            IEnumerable<object> objects = new List<string>();
objects.ForAll(x => Console.WriteLine(x));
objects.ForAll(Console.WriteLine);

  6.有时候,使用接口可以帮助我们避免 struct 类型的拆箱所带来的代价。

二十三、理解接口方法和虚方法的区别

  1.在基类中实现一个接口时,派生类需要使用 new 来隐藏对基类方法的使用。

  2.可以将基类接口的方法申明为虚方法,然后在派生类中实现。

二十四、用委托实现回调

  1.类之间需要通信时,并且我们期望一种比接口所提供的更为松散的耦合机制时,委托就是最佳的选择。

  2.多播委托会把所有添加到该委托中的目标函数组合成一个单一的调用。需要注意的是:

  (1)如果有委托调用出现异常,那么就不能保证安全;

  (2)整个调用的返回值将为最后一个函数调用的返回值。

  3.在多播委托调用的过程中,每个目标会被依次调用。委托对象本身不会捕捉任何异常。因此,任何目标抛出的异常都会结束委托链的调用。

二十五、用事件模式实现通知

  1..NET 中的事件就是观察者模式的一个语法上的快捷实现。

  2.使用 System.ComponentModel.EventHandlerList 容器来存储各个事件处理器,在类型中包含大量事件时可以使用他来隐藏所有事件的复杂性。

  3.EventHandlerList并没有提供内建的泛型实现,可以自行基于 Dictionary 构建。

二十六、避免返回对内部类对象的引用

  1.4 种策略可以防止类型的内部数据结构遭受有意或无意的修改:值类型、常量类型、接口和包装器(wrapper):

  (1)当客户代码通过属性来访问值类型成员时,实际返回的是值类型的副本。

  (2)常量类型,如:System.String 也是安全的。

  (3)通过接口向外界暴露类的功能,即可尽量地避免内部数据遭受无意的更改,定义接口将访问限制在一个子集中从而最小化对对象内部状态的破坏。

  (4)仅暴露包装器,定义一个包装器对象来限制另一个对象的访问。

  2.通过使用接口、包装器对象或值类型向外界提供内部的私有数据,即可限制外界对这些数据的访问能力。

二十七、让类型支持序列化

  1.[Serializable] 特性支持序列化。

  2.[NonSerialized] 特性阻止序列化。

二十八、提供组粒度的因特网服务 API

  1.程序中最耗时的是与远程服务器之间的数据传输,每次通过网络获取一小段数据时,应用程序都需要等待网络传输的过程,API 的粒度越细,所花费在等待数据返回上的额外时间也就越多。

  2.我们希望同时降低通信的频率以及每次通信时所传递的数据量。但这两个目标往往不可兼得,因此必须做出取舍。尽量不要走两个极端,可以适当选择较少的通信次数,尽量一次传输更多的数据。

二十九、支持泛型协变和逆变

  1.类型变体:协变和逆变。定义了在某种情况下,某个类型可以代替另一个类型进行使用。若不能将一个类型替换成另一个,则这个类型就叫不变量,在 C# 4.0 之前,所有泛型类型都不变量。你应该尽可能地让泛型接口和泛型委托支持协变和逆变。

  2.协变和逆变是两种不同形式的类型替换。若某个返回的类型可以由派生类型替换,那么这个类型就是支持协变的。若某个参数类型可以由其基类替换,那么这个类型就是支持逆变的。

  3.在可能的情况下为泛型接口和委托添加上 in 和 out 参数进行修饰。

  4.因为 IList<T> 没有添加 in 或 out 修饰 T,所以必须使用精确的类型匹配。

本系列

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

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

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

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


【博主】反骨仔

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

【参考】《Effective C#》

[.NET] 《Effective C#》快速笔记(三)- 使用 C# 表达设计的更多相关文章

  1. Android Studio安卓学习笔记(三)Android用户界面的设计布局与组件(一)用户界面布局设计(1)

    当我们创建了一个安卓项目后,我们会发现真正建立一个完善的安卓项目并不是想象的那么容易.其实和设计GUI可视化界面一样,开发安卓也需要考虑很多方面,主要考虑的还是界面布局和需要的组件. 一:Androi ...

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

    目录 二十一.限制类型的可见性 二十二.通过定义并实现接口替代继承 二十三.理解接口方法和虚方法的区别 二十四.用委托实现回调 二十五.用事件模式实现通知 二十六.避免返回对内部类对象的引用 二十七. ...

  3. [.NET] 《Effective C#》快速笔记(四)- 使用框架

    <Effective C#>快速笔记(四)- 使用框架 .NET 是一个类库,你了解的越多,自己需要编写的代码就越少. 目录 三十.使用重写而不是事件处理函数 三十一.使用 ICompar ...

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

    <Effective C#>快速笔记 - C# 中的动态编程 静态类型和动态类型各有所长,静态类型能够让编译器帮你找出更多的错误,因为编译器能够在编译时进行大部分的检查工作.C# 是一种静 ...

  5. [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充

    <Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...

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

    <Effective C#>快速笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内 ...

  7. [.NET] 《Effective C#》快速笔记(一)- C# 语言习惯

    <Effective C#>快速笔记(一)- C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 ...

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

    目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Conditional ...

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

    目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 四十九.实现与 CLS 兼容的程序集 五十.实现小尺寸.高内聚的程序集 这是 ...

随机推荐

  1. 算法模板——LCA(最近公共祖先)

    实现的功能如下——在一个N个点的无环图中,共有N-1条边,M个访问中每次询问两个点的距离 原理——既然N个点,N-1条边,则说明这是一棵树,而且联通.所以以1为根节点DFS建树,然后通过求两点的LCA ...

  2. 常见Android面试题及答案(详细整理)

    1. 请描述一下Activity 生命周期. 答: 如下图所示.共有七个周期函数,按顺序分别是: onCreate(), onStart(), onRestart(), onResume(), onP ...

  3. Django REST framework使用ViewSets的自定义路由实现过程

    在Django中使用基于类的视图(ClassView),类中所定义的方法名称与Http的请求方法相对应,才能基于路由将请求分发(dispatch)到ClassView中的方法进行处理,而Django ...

  4. CSS用足够大的纯色内阴影去覆盖掉谷歌input记住账号或密码时默认出现的黄色背景

    在谷歌浏览器会默认记住账号,而记住账号之后其input的背景会变成黄色,解决的办法如下: input:-webkit-autofill { -webkit-box-shadow: 0px 1000px ...

  5. Bootsrap 的 Carousel

    一.简介 Carousel 就是指轮播图,这里 有完整的代码例子.它可以很简单的就构造出来,结构如下: div.carousel.slide[data-ride="carousel" ...

  6. 前端资讯周报 3.13 - 3.19: WebVR来了!以及如何优化scroll事件性能

    每周一我都会分享上一周我订阅的技术站点中,和解决问题的过程中阅读到的值得分享的文章.这是迫使我学习的一个动力 本周推荐 Minecraft in WebVR with HTML Using A-Fra ...

  7. ThinkPHP3.2.3版本验证码异步第二次验证时失败的问题解决

    最近在用TP3.2.3做一个小项目,纠结于验证码验证问题,重点在于二次验证,举个例子就是常见的登录页面上有个验证码输入框,当用户输入验证码并且鼠标点击在这个输入框之外时候,触发onblur事件,然后a ...

  8. pyqt样式表语法笔记(中)--原创

    pyqt样式表语法笔记(中) pyqt QSS python 样式表 一.弹窗 在日常的各种桌面软件的使用中,我们都会碰到弹窗.例如注册,登录的时候,会有相应的信息弹窗,这里就以信息收集弹窗为例进行弹 ...

  9. win32最简单的htmlayout图形界面demo

    1,下载HTMLayoutSDK,放在workspace. SDK下载地址:http://www.terrainformatica.com/htmlayout/HTMLayoutSDK.zip 2,v ...

  10. Struts2.5简单使用入门

    今天学了Struts2.5最新版的,老师在黑板上讲的很是简单,也很是容易,简单的就实现了.可是课下让我们自己弄,自己无论如何都无法运行成功,一直提示404.偶然间灵机一动,改了一下那个文件就好了.希望 ...