我勒个去……过了整整仨月,才看完一章,我是有多懒了。。。。不过最近工作忙,而且新房还装修。一体检还查出个过度疲劳。似乎卖苦肉计也没啥意思哈。。。。以后尽量勤奋点吧!嗯啊~
Chapter 2 .NET Resource Management
     GC通过定义“代”的概念来优化回收工作。可以筛选出更加有“潜质”的回收对象。所有自上次GC以后创建的对象是第0代。经过一次GC后仍存在的,升级为第1代。再经过一次GC后仍存在的升级为第2代(最高)。每一次GC都会检查第0代的对象,大约10次GC才会检测一次第1代的,而大约100次GC才会检测一次第2代的对象。这样设计,是为了将局部变量快速地遍历回收,同时保证一些全局的一直被使用的对象不每次都被遍历。
     在C#中,使用Finalizer来释放资源并不是一个好主意。因为Finalizer只有在对象被GC时才被调用。所以被调用的时机是未知的。
     存在Finalizer的对象,必须要等到下一个GC周期才能被析构。因为Finalizer不能在GC的线程中被调用。GC会将存在Finalizer的对象存入一个队列,再开一个线程给他们。所以Finalizer会使本可以被迅速回收的局部变量的代数迅速升级。
  • Prefer Member Initializer To  Assignment Statements
    • 随着类的构造函数的增多,可能会造成一些成员变量没有被同步地初始化的情况。避免这种情况的一个解决办法就是在声明它们时就初始化。编译器会将声明时初始化编译为所有构造函数方法体之前的一段初始化代码,而且是按照你定义的顺序。这样保证构造函数中所有声明初始化已经完成。
    • 但是,当你需要给变量初始化为0或者null时,不要使用声明初始化。如果不使用,系统会在较低的level为这片内存区域设置为0或者null。这是非常高效的。反之,编译器需要在代码中加入额外的赋值指令。这样做不错,只是效率不如前者高。
    • 当你需要在构造函数中根据参数初始化一些成员变量时,不要使用声明初始化。因为这样声明初始化的对象生成后直接就被GC掉。
    • 当你需要捕捉初始化的异常时,不要使用声明初始化。因为它无法放在try...catch中。
  • Use Proper Initialization For Static Class Member
    • 静态构造函数在对应的类型第一次访问之前被调用。所以可以用来进行需要一些逻辑的静态初始化。例如:异常捕获。
  • Utilize using and try/finalize for Resource Cleanup
    • 所有含有非托管资源的类型都实现的IDisposable接口。应当显示调用他们的Dispose()方法来释放内存。
    • 当对象抛出异常时,Dispose()可能没有被调用。最简单的解决方法是使用using将非托管对象包围起来。using会在编译时生成try/finalize语句块。
    • using(){}中的对象类型必须是实现了IDisposable接口的。如果不是,可以用as骗过编译器。但效果相当于using(null){},不会有任何意义。
    • 当有多个非托管对象同时出现时,可以自己手写try/finalize语句块。嵌套using()也成,只是结构会比较难看。。。
    • 也可以用Close()来释放非托管资源。但与Dispose()不同的时,Close()在释放资源后不会将它从GC的Finalize Queue中移除。所以Dispose()比Close()更好。
    • Dispose()不会将对象从内存移除,只是让对象释放非托管资源,例如数据库连接。这时,这块内存还在,但是数据库连接已经断开了。
  • Avoid Creating Unnecessary Objects
    • 作者最想说的就是不要在方法里面创建引用类型的对象,尤其是频繁调用的方法。如何避免呢,有下面三个方法。
    • 把一直重复使用的对象提升为全局对象,避免每次都创建。
    • 一些常量的对象写成静态属性。只在获取时创建。
    • 对于一些不可变的对象,实现一个可以构造器。例如string和StringBuilder。
  • Implement the Standard Dispose Pattern
    • 实现你自己的Dispose模式时,一定要写Finalizer,虽然会有一些性能损耗,但可以保证非托管资源一定能被释放。
    • 实现Dispose模式需要做4件事:
      • 释放非托管资源
      • 释放托管资源
      • 设置一个标志位,标明这个对象已经被Dispose。其它方法被调用时,抛出ObjectDisposedException。
      • 触发Finalization。
    • 只在需要的时候写Finalization,否则会造成性能开销。
    • 永远不要在Finalizer和Dispose中做释放资源以外的事情。
    • 可以写一个Helper method:void Dispose(bool isDisposing)。
public class MyResourceHog : IDisposable
{
private bool alreadyDisposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool isDisposing)
{
if (alreadyDisposed)
return;
if (isDisposing)
{
// elided: free managed resources here.
}
// elided: free unmanaged resources here.
alreadyDisposed = true;
}
public void ExampleMethod()
{
if (alreadyDisposed)
throw new ObjectDisposedException(
"MyResourceHog",
"Called Example Method on Disposed object");
// remainder elided.
}
}     
  • Distinguish between Value Types and Reference Types
    • 值类型一般用于存储数据,而引用类型一般用于包含行为、实现继承和多态。
    • 决定一个自定义的类型是值类型还是引用类型很重要。将一个引用类型改为值类型会带来深远的影响。值类型将不再支持继承和多态,而且作为参数或返回值传递时,会产生一个新的对象。
    • 如果拿不定主意,选择引用类型。
  • Ensure 0 is a Valid State for Value Types
    • 所有的值类型都会在初始化时将内部的值置为0,这是C#语言的特性,你无法改变,你只能去适应。
    • 对于enum,最好将0作为一个合理的值。否则EnumType aaa = new EnumType();这样的语句会造成一个无效的enum值。如果是作为位操作使用,请将0作为None使用,即每一种情况都没有选中。
  • Prefer Immutable Atomic Value Types
    • 不可变的数据类型更易于维护。然而创建不可变数据并不容易。防止struct中的字段被滥改,可以使用属性加以控制。但是过多的属性也带来过多的隐患。可以将属性的set设为private。只在构造函数中进行赋值。如果更严格一点,可以将字段设为readonly,并且去掉属性的set。
    • 对于struct中的引用类型要加倍小心。它们可能从外部被改变。保险的解决方案是在构造函数中进行复制,或者在属性的get时进行复制。
    • 其它的防止struct中的字段被改变的方式两个。一个是使用工厂方法。还有就是将多部操作进行封装来构造不可变数据,例如StringBuilder和string。

转载于:https://www.cnblogs.com/sigmadruid/p/5054330.html

Effective C#(二)相关推荐

  1. swift/dart代码规范检查工具介绍

    swift/dart代码规范检查工具介绍 简介: 本篇主要介绍swift和dart代码规范检查工具,以及他们的工作原理,操作过程,代码规范规则. 1 swift代码检查工具-swiftlint 1.1 ...

  2. 机器学习笔记(九)聚类算法Birch和层次聚类Hierarchical clustering

    本篇文章我们继续介绍另一种聚类算法--Birch模型,相对于K-means和DBSCAN,Birch的应用并没有那么广泛,不过它也有一些独特的优势,Birch算法比较适合于数据量大,类别数K也比较多的 ...

  3. 【Dart】Dart代码静态检查

    介绍 代码检查可以有效的提高代码质量,更进一步的说代码检查不仅仅是为了提高代码质量,已深入到代码程序的逻辑检查.内存使用情况的检查甚至更高层面的检查,很大程度上影响了程序的功能和性能. 代码检查分类 ...

  4. Effective Java读书笔记(二)

    Effective Java 读书笔记 (二) 创建和销毁对象 遇到多个构造器参数时要考虑使用构建器 创建和销毁对象 何时以及如何创建对象? 何时以及如何避免创建对象? 如何确保它们能够适时地销毁? ...

  5. 声明及赋值_重述《Effective C++》二——构造、析构、赋值运算

    关于本专栏,请看为什么写这个专栏.如果你想阅读带有条款目录的文章,欢迎访问我的主页. 构造和析构一方面是对象的诞生和终结:另一方面,它们也意味着资源的开辟和归还.这些操作犯错误会导致深远的后果--你需 ...

  6. Effective Java读书笔记二:枚举和注解

    第30条:用enum代替int常量 当需要一组固定常量的时候,应该使用enum代替int常量,除了对于手机登资源有限的设备应该酌情考虑enum的性能弱势之外. 第31条:用实例域代替序数 枚举的ord ...

  7. Effective Java之多个构造参数考虑用构建器(二)

    静态工厂方法和构造器都有一个共同的特点–>无法扩展到大量的参数. 对于大量的参数类,我们有以下方案: 1.重叠构造器.这个源码中经常可以看到,例如HashMap: public HashMap( ...

  8. Effective C++读书摘要--Implementations二

    <Item29> Strive for exception-safe code. 1.如下面的代码 class PrettyMenu { public:...void changeBack ...

  9. C++::My Effective C++ (二)

    C++::My Effective C++ (1)学会给一条冗长的语句换行,比如在等号的右侧空格处换行 typedef 冗长的类模板实例为简洁的类型 typedef std::pair<size ...

  10. Effective Java读书笔记---二、创建和销毁对象

    二.创建和销毁对象 何时以及如何创建对象, 何时以及如何避免创建对象, 如何确保它们能够适时地销毁, 如何管理对象销毁之前必须进行的各种清理动作 1.用静态工厂方法代替构造器 优势: 它们有名称 不必 ...

最新文章

  1. 百度Q3财报里的“大生意”
  2. mysql 连接url中useUnicode=truecharacterEncoding=UTF-8 的作用
  3. guava_使用Google Guava Cache进行本地缓存
  4. 每日一皮:据说PM就是这样忍受你的!
  5. HDU2204 Eddy's爱好(容斥原理)
  6. 01.05第六周周总结
  7. 查看journalnode节点状态信息_OpenStack Cinder服务状态排错
  8. 两个list怎么对比数据_基于日志的回放对比系统设计
  9. 演练 开心餐厅 0929
  10. 荣耀 Magicbook Pro 锐龙版搭载深度操作系统桌面版
  11. web安全day25:linux的NAT网络配置和yum的配置和使用
  12. 昂贵的聘礼 - poj 1062 (Dijkstra+枚举)
  13. android点击禁止获取权限,Android 6 Permissions =禁用权限时崩溃并返回应用程序
  14. 1024程序员节,160元买400元图书专属优惠券,速来
  15. OSPF协议邻居(Neighbor)与邻接(Adjacency)关系
  16. oracle中三元运算符,三目运算符简介 - ZICK_ZEON的个人空间 - OSCHINA - 中文开源技术交流社区...
  17. C - char与wchar_t(TCHAR/WCHAR)之间的相互转换
  18. 离散对数和椭圆曲线加密原理
  19. 2006-2020年各省研究与试验发展(RD)数据
  20. 私服github开源项目

热门文章

  1. C语言代码规范(编程规范)
  2. 2019牛客暑期多校训练营(第五场)F - maximum clique 1 (最大团:补图最大独立集)
  3. UDP对应的应用层协议之DNS、DHCP
  4. mysql 删除外键
  5. C++ 中的this指针详解及实例
  6. Linux的进程/线程间通信方式总结
  7. 得到照片_大叔偷别人羞羞的照片画画,添油加醋后,却得到无数人点赞!
  8. 利用sqoop将hive数据导入导出数据到mysql
  9. eclipse插件egit安装使用
  10. 在Excel中如何引用其他的工作表或者工作簿