zoukankan      html  css  js  c++  java
  • Effective C#(一)

    最近在读Effective C#这本书。写的简直太TM好了。反正读了很有收获啦,强力推荐。为了防止狗熊掰棒子,就写一下读书笔记吧。自己感觉还是比网上的一些写的全的。但能不能坚持下去就不好说啦~~所以,且看且珍惜哦~

    直接从Evernote复制过来的~凑合看哈~

      • Use Properties Instead of Accessible Data Members
        • 属性会被编译器编译成方法,所以支持一些成员变量不支持的特性,例如数据绑定、多线程操作。还可以将属性设为abstract或virtual。另外属性里还可以进行数据验证操作。
        • 在属性内部的操作中,不应当写过度复杂或消耗性能的操作。
        • 可以实现索引器属性。写法是public object this[object index]。属性名必须是this。也可以实现多个索引,例如public Vector2 this[float x, float y]。
        • 属性的调用并不会比直接的数据变量调用多消耗多少性能。
      • Prefer readonly to const
        • readonly是运行时常量,而const是编译时常量。
        • readonly 可以是任意类型,而const只能是基本数据类型(int, float, string, bool)。
        • readonly是取指定数据,而const是直接将数据值进行替换。因此const有一定的性能的优势。但比readonly灵活性差。
        • const隐含指定了是静态的。
        • 在主程序集引用另一个程序集的const时,如果这个const的值有了改动,并替换了程序集,主程序集中的值并不会有变化。除非重新编译主程序集。所以还是用readonly更安全啊~
        • 可以使用const来记录版本号。因为它只在编译时有改动。
      • Prefer the is or as to casts
        • is或as仅仅进行类型判断,如果判断失败,返回null。 而进行cast时,如果没有用户自定义的转换,则会编译报错。而如果运行时无法转换,则会抛出异常。所以进行cast时,往往需要使用try...catch。
        • as不能使用在值类型变量上。所以使用前需要用is判断。
      • Use Conditional Attribute Instead Of #if
        • 过多使用#if和#endif会使代码结构混乱,难以维护。而且留下空的方法体也会造成额外的开销。
        • Conditional Attribute只能使用在方法体上,而且该方法必须返回值为void。
        • 有Conditional Attribute的方法,在条件不满足时,不会被调用。参数中的表达式也不会执行。
      • Always Provide ToString()
        • 对每个类都重写ToString()方法。默认的ToString()的返回值没有什么意义。
      • Understand the relationships among the many different concepts of equality.
        • C#有4种等于判断方法:static bool RefereceEquals(object left, object right), static bool Equals(object left, object right), virtual bool Equals(object right), static bool operator==(MyClass left, MyClass right)。永远不要重写前两个方法。
        • RefereceEquals()判断两个变量是否引用相同的对象。所以,当使用值类型作为参数时,永远返回false。
        • Object.Equals()判断两个未知类型的变量是否相等。
        • ValueType.Equals()会使用反射进行等于判断。所以最好重载自定义的ValueType.Equals()。
        • Equals()实例方法只有在需要进行内容判断而不是引用判断时才有必要。而且要遵从固定的格式,实现IEquatable<T>接口。
          • 永远不要抛出异常,因为没意义。。。
          • public class Foo : IEquatable<Foo>
            {
                 public override bool Equals(object right)
                 {
                      // check null:
                      // this pointer is never null in C# methods.
                      if (object.ReferenceEquals(right, null))
                           return false;
                      if (object.ReferenceEquals(this, right))
                           return true;
                      // Discussed below.
                      if (this.GetType() != right.GetType())
                           return false;
                      // Compare this type's contents here:
                           return this.Equals(right as Foo);
                 }
                 #region IEquatable<Foo> Members
                 public bool Equals(Foo other)
                 {
                      // elided.
                      return true;
                 }
                 #endregion
            }
        • 当定义自己的值类型时,需要自定义operator==(),因为值类型的等于判断会默认使用反射。
      • Understande the pitfall of GetHashCode()
        • GetHashCode()只在哈希容器的key值中使用。无论值类型还是引用类型的对象,都没有既准确又高效的实现。
        • 所有对GetHashCode()的重载都必须遵从以下原则:
          • 两个相等的对象(根据operator==()定义)必须返回相同的哈希值。
          • 无论对对象有怎样的操作,GetHashCode()都返回相同的哈希值。
          • 根据输入得到的哈希值应当平均地分布在整个整数值的值域内。
        • 每一个对象都有一个字段记录对象编号。在构造函数中赋值,并且不能更改。Object.GetHashColde()就是返回这个值。
        • ValueType.GetHashCode()返回第一个字段的GetHashCode()。如果第一个字段不是不可变的,这会带来隐患!
      • Prefer query syntax to loops
        • 查询标记比循环更易懂易维护。循环更注重的是操作的行为,而不是程序设计的意图。
      • Avoid conversion operator in your APIs
        • 类型转换操作符可能带来隐患。因为创造的对象是临时的。
          static public implicit operator Ellipse(Circle c)
          {
               return new Ellipse(c.center, c.center, c.radius, c.radius);
          }
          你对这个创建的Ellipse对象的所有操作都没有意义,因为这个对象只是临时的。例如下面这个方法:
          public static void Flatten(Ellipse e)
          {
               e.R1 /= 2;
               e.R2 *= 2;
          }
          调用这个方法后,你的Circle半径并不会有改变。
      • Use optional parameters to minimize your  overloads
        • 命名参数可以给指定的含默认值的参数赋值。一个方法如果有100个含默认值的参数,而你要给最后一个参数赋值,使用命名参数就可以避免把前面99个都写一遍了。
        • 而且,使用命名参数可以大大减少重载的工作量,但能带来一样的灵活度。
        • 使用命名参数可以避免相同类型的参数因为顺序导致的错误。例如下面这段代码:
          private void SetName(string lastName, string firstName)
          {
          }
          SetName(lastName: "Wagner", firstName: "Bill");
        • 但是命名参数有隐患。当给参数重命名时,会导致方法调用失效。需要手动改。
      • Understand the attraction of small functions
        • C#代码会被编译成IL的Assembly,而Assembly会在运行时将将要执行的方法编译成对应平台的机器码。
        • 由于方法只有被执行时才被编译,所以写一些小的方法会带来性能的提升。
        • 而且小的方法(方法体里面不能有try...catch或者是virtual)可以被内联。是否内联由JIT决定。
        • 使用频率较高的局部变量有可能被放置到寄存器进行优化。因此使用更少的局部变量,可以让JIT更好地决定。

     

  • 相关阅读:
    SLAM+语音机器人DIY系列:(二)ROS入门——3.在ubuntu16.04中安装ROS kinetic
    SLAM+语音机器人DIY系列:(二)ROS入门——2.ROS系统整体架构
    2017年 年计划
    125. Valid Palindrome
    一道多树递归面试题
    顺序表查找和有序表查找
    c++中常见概念、关键字等的区别
    两个栈实现一个队列,两个队列实现一个栈
    150. Evaluate Reverse Polish Notation
    堆排序
  • 原文地址:https://www.cnblogs.com/sigmadruid/p/4817052.html
Copyright © 2011-2022 走看看