[.NET] 《Effective C#》急迅笔记(二)- .NET 财富托管

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

C语言 1

 

简介

  续 《Effective C#》读书笔记(一)- C#
语言习惯

  .NET 中,GC
会帮助大家管理内部存款和储蓄器,大家并不必要去担心内部存款和储蓄器泄漏,财富分配和指针早先化等难题。可是,它也不用万能,因为非托管能源供给大家休戚相关开始展览清理,如文件句柄、数据库连接、GDI+
对象和COM 对象等。

 

目录

  • 十二 、推荐应用成员起头化器而不是赋值语句
  • 十三 、正确地起初化静态成员变量
  • 十肆 、尽量缩短重复的起先化逻辑
  • 十⑤ 、使用 using 和 try/finally 清理财富
  • 十陆 、幸免创造非供给的靶子
  • 十柒 、达成规范的灭绝格局
  • 十八 、区分值类型和引用类型
  • 十九 、保险 0 为值类型的卓有成效处境
  • 二⑩ 、保证值类型的常量性和原子性

 

十贰 、推荐使用成员早先化器而不是赋值语句

  1.分子起首化器:在评释变量时就展开开端化,而不是在种种构造函数中开始展览。

  2.以下 3 种情景,应防止选择成员发轫化器:

  (1)当您想要初始化对象为 0 或 null
时。因为系统暗中认可的开始化学工业作(在拥有代码执行前)会将全体设置为 0 或
null,大家做的是一步多余的操作。而且,就算是值类型,那么品质尤其差。

            MyValueType myVal1; //初始化为 0
            MyValueType myVal2 = new MyValueType(); //也是 0

  那两条语句都将变量初阶化为 0,但第③条是经过设置蕴涵 myVal1
的这一块内部存储器为 0 完结的,而第③条利用的是 initobj 那条 IL 指令,导致了对
myVal2 变量的一次装拆箱操作,那将占据额外品质与时光。

  (2)必要对同3个变量执行差异的伊始化格局:

    class Program
    {
        /// <summary>
        /// 声明并初始化
        /// </summary>
        private List<string> _lables = new List<string>();

        public Program() { }

        public Program(int capacity)
        {
            _lables = new List<string>(capacity);
        }
    }

  开端化该类时,要是使用的是带 capacity 的构造函数,那么
List<string> 对象表示先导化了 2 次,头2个就改成了排泄物对象。

  (3)将初阶化代码放在构造函数的适宜理由:能够一本万利分外管理
try-catch。

 

十三 、正确地初叶化静态成员变量

  1.在使用项指标实例在此之前,就相应开首化该类型的有着静态成员变量。静态构造函数是3个异样的函数,将在任何兼具办法、变量或质量被第二遍访问从前实施。你能够运用那几个函数来开首化静态变量和兑现单例情势等操作。

  2.静态起初化器和静态构造函数是开始化类的静态成员的顶级采纳。

  3.用到静态构造函数而不是静态开首化器最广大的说辞是足以捕捉和处理非常。

 

十四 、尽量收缩重复的起始化逻辑

  1.假设三个构造函数包含类似的逻辑,大家应将其领取到1个集体的构造函数中,那样可避防止代码重复,也足以动用构造函数初阶化器生成更高效的代码。

    class MyClass
    {
        private List<string> _lables;
        private string _name;

        public MyClass() : this(0, string.Empty)
        {

        }

        public MyClass(int capacity = 0, string name = "")
        {
            _lables = new List<string>(capacity);
            _name = name;
        }
    }

C语言,  第二个构造函数使用了 “” 来交给 name 的默许值,而不是利用
string.Empty ,因为 string.Empty 并不是1个编写翻译期的常量,而是二个概念在
string 类中的静态属性,所以无法用作参数的暗中同意值。

  2.创设某些项目的第②个实例时所开始展览的操作顺序:

  (1)静态变量设置为 0 ;

  (2)执行静态变量开始化器;

  (3)执行基类的静态构造函数;

  (4)执行静态构造函数;

  (5)实例变量设置为 0;

  (6)执行实例变量初叶化器;

  (7)执行基类中十分的实例构造函数;

  (8)执行实例构造函数。

  3.施用开首化器来初阶化简单的财富,使用构造函数来先导化需求复杂逻辑的成员,同事不要遗忘将调用抽取到三个构造函数中,以便裁减重复。

  4.构造函数概念中只能利用叁个开端化器,要么使用 This()
委托给另一个构造函数,要么采用 base() 调用基类的构造函数。

 

十5、使用 using 和 try/finally 清理能源

  1.使用了非托管系统能源的种类必须出示地运用 IDisposable 接口的
Dispose() 来刑满释放解除劳教,Using() 语句将生成贰个Try/finally 块。

 

十6、幸免创立非须求的靶子

  1.GC
可以很好地管理内存,但不论多高效,分配和销毁堆上的目标总会成本非常长日子,假设过多的创始引用对象,那么会对程序的性质爆发严重的影响。

        public void Paint()
        {
            using (var myFont = new Font("Arial", 10.0f))
            {
                Console.WriteLine($"使用 {myFont} 进行绘画");
            }
        }

  假使该方法被特别频仍地调用。每便调用时都会成立另三个 Font
对象,但它含有的剧情和事先的是截然一致。GC
每一回都要为你清理那几个污源,分明是拾贰分低效的。

  能够把 myFont 提高为静态变量。

        private readonly static Font _myFont = new Font("Arial", 10.0f);

        public void Paint()
        {
            Console.WriteLine($"使用 {_myFont} 进行绘画");
        }

  2.暴跌程序中创设对象数量的章程。

  (1)将常用的一些变量升高为成员变量;

  (2)提供3个类,存放有个别项目常用实例的单例对象。

   3.用 StringBuilder 进行理并答复杂的字符串操作

 

十⑦ 、完毕规范的灭绝方式

  1.IDisposable.Dispose() 方法的贯彻中要求形成如下 4 个职务:

  (1)释放具有非托管能源;

  (2)释放具有托管财富,包罗自由事件监听程序;

  (3)设定多少个状态标志,表示该指标已经被灭绝;

  (4)跳过停止操作,调用 GC.SuppressFinalize(this) 即可。

 

十⑧ 、区分值类型和引用类型

  1.一般的话,大家创立的多数是引用类型。

  2.规定创造值类型的原则有 4 个 

  (1)该项目标首要任务在于数量存款和储蓄;

  (2)该项指标国有接口都以由访问其数据成员属性定义的呢?

  (3)你明确该品种绝不会有派生类型吗?

  (4)你规定该品种永远都不须求多态帮忙啊?

  3.用值类型表示底层存储数据的类型,用引用类型来封装程序的作为。

  4.若是您对品种未来的用途不鲜明,应选用引用类型。

 

十玖 、有限支撑 0 为值类型的有用景况

  1..NET 系统的暗中认可初叶化进程会将兼具的指标设置为 0,提议将 0
作为枚举类型的私下认可值。

  2.枚举(enum)必须将 0
设定为枚举值的1个实惠选用。全部的枚举值都派生自
System.ValueType。枚举的私下认可值初阶于 0。

  3.在创设自定义枚举值时,请保管 0
是一个可行的选项。若您定义的是标识(flag),那么可将 0
定义为没有入选任何的标志。

    enum Week
    {
        None = 0,
        Monday = 1,
        Tuesday = 2,
        Wednesday = 3,
        Thursday = 4,
        Friday = 5,
        Saturday = 6,
        Sunday = 7
    }

 

二10、保障值类型的常量性和原子性

  1.常量性:自创制后,其值保持不变。因为不可能更改内部情形,就可以节省许多不要求的失实检查,它也是线程安全的,也得以高枕无忧地展露给外界,因为调用者不能更改指标的内部景色。

  2.安插常量类型时,要力保没有此外漏洞会导致当中情形被外面更改。因为值类型不可能派生,所以不要担心会合临派生类影响。

  可是,即便常量中是可变的引用类型字段的话,大家就相应对那个可变类型实行防御性的复制。

    class MyClass
    {
        private readonly object[] _objs;

        public MyClass(ICollection<object> objs)
        {
            _objs = new object[objs.Count];
            objs.CopyTo(_objs, 0);  //复制
        }

        public IEnumerable<object> Objs => _objs;
    }

 

        static void Main(string[] args)
        {
            var objs = new object[10];
            var myClass = new MyClass(objs);
            objs[1] = "hi";

            Console.WriteLine(myClass.Objs.ToArray()[1]);

            Console.Read();
        }

  因为数组是引用类型,即使不应用 CopyTo 复制2个副本的话,在外表的
objs 修改就会直接影响 MyClass 中的
_objs,因为她俩本着的都是同三个引用。

  2.永不盲目地对每3个属性都助长 { get; set; }。

 

本系列

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

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

  《Effective C#》急迅笔记(三)- 使用 C#
表明设计

  《Effective C#》急速笔记(四) –
使用框架

  《Effective C#》火速笔记(五) – C#
中的动态编制程序

  《Effective C#》赶快笔记(六) – C#
高效编制程序要点补充

 

 


【博主】反骨仔

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