阅读笔记_《effective-csharp》
来源:互联网 发布:国产女装品牌知乎 编辑:程序博客网 时间:2024/04/30 19:23
记录一下 《effective-csharp》 这本书里觉得比较有用的东东
gitbook:https://wizardforcel.gitbooks.io/effective-csharp/content/
索引器(indexers )
类似数组下标的方式 在类中使用
class Abs { public Dictionary<string, string> _map = new Dictionary<string, string>(); public string this[string key] { get { return _map.ContainsKey(key) ? _map[key] : null; } set { _map.Add(key, value); } } } Abs a = new Abs(); a["aaa"] = "sdf";
属性访问器(getter setter)
在写c++的时访问属性一般都会提供个 getter setter 方法,方法体不大的时候编译器会做 inline 优化,在csharp中有这样的 语法糖,它提供了 inline 优化
class AAA { int mA = 0; public int A { get { return mA; } set { mA = value; } } }
如果不想被 inline 优化,可以使用 System.Runtime.CompilerServices.MethodImpl 特性, 指定方法不被内联
[MethodImpl(MethodImplOptions.NoInlining)]public int A(){}
不会被 inline 优化的情况:虚函数 或者 包含 try/catch 的函数
偏爱 readonly 而不是 const
C# 有两种常量:编译时常量 const 和 运行时常量 readonly。
区别:
- 编译时常量 会比 编译时常量 稍微快点, 但更不灵活
- 编译时常量 还可以在方法体中声明。运行时常量 不能在方法体重声明
- 编译时常量 和 运行时常量 访问方式不同导致不同的行为。 在目标代码中 编译时常量 会被替换成 常量值;运行时常量 的值是在运行时得到的。 当你引用一个只读(read-only) 常量, IL 会引用一个readonly 变量而不是直接使用值
- 编译时常量只能在基本类型(内建整数和浮点数类型) , 枚举类型, 或字符串。 编译时常量要求类能用有意义的常量赋值初始化。 而只有基本类型才能在 IL 代码中使用常量(literal values) 来替换。 不能使用使用 new 操作法初始化编译时常量 ,即使它是一个值类型 。
- const编译时 编译到程序集,如果别的程序集使用了这个变量,这个变量将不会有任何改变;而readonly是运行时get到值,所以readonly跟灵活
示例:
// Compile time constant:public const int Millennium = 2000;// Runtime constant:public static readonly int ThisYear = 2004;
选择 is 或 as 而不是强制类型转换
使用as做类型转换,而不是强制装换(XXX)obj,如果obj没有继承关系,as编译时会报错,而(XXX)obj不会。
不能使用as的情况:参数为 值类型,此时可以用is来判断。(is只用于as无法使用的情况,否则多余,如果知道参数是引用类型就用 as)
示例
object o = Factory.GetObject();MyType t = o as MyType;if (t != null) {//Do somethind about t.}
使用条件特性(conditional attribute) 代替 #if/#endif
假如调试代码是 CheckState 函数里的
[Conditional("DEBUG")]private void CheckState(){// same code as above}
如果 DEBUG 变量被定义, 你的代码编译出来是这样的
public string LastName { get { CheckState(); return lastName; } }
如果 DEBUG 变量 没有 定义, 你的代码编译出来是这样的
public string LastName { get { return lastName; } }
如果使用 #if/#endif 块包住,也会产生一次 CheckState 函数的调用,即使 DEBUG 没有定义
private void CheckState(){#if// same code as above#endif}
Conditional 只能使用在 void 返回值的函数中,否则编译错误。
这种是 或 的表达式,如果要表达 与,拆分成两个方法,各用一个红
[Conditional("DEBUG"), Conditional("DEBUG222")]private void CheckState() {}//等价于#if DEBUG || DEBUG222#endif
使用恰当的方式对静态成员进行初始化
静态初始化语法 会比 静态构造函数 更早执行,静态初始化语法 和 静态构造函数 是最干净, 最清晰的方式去初始化静态成员变量
实例第一次构造对象时的顺序
- static 变量默认存储为0。
- static 变量初始化执行。
- 基类静态构造函数执行。
- 静态构造函数执行。
实例成员变量默认存储为0。
实例成员变量初始化执行。
- 恰当的基类实例构造函数执行。
实例构造函数执行。
- 后续同一类型的对象初始化从第5步开始因为类初始化只会执行一次。 而且, 步骤6和7会被优化构造函数初始化语法会引起编译器移除重复的指令。
使用构造函数链
构造函数时 调用其他构造函数,减少各个构造函数中重复的初始化代码。类似重载函数的概念
public class MyClass {// collection of data private List<Circle> coll; private string name; public MyClass() : this(0, string.Empty) { } public MyClass(int initialCount = 0, string name = "") { coll = (initialCount > 0) ? new List<Circle>(initialCount) : new List<Circle>(); this.name = name; } }
using 语法糖
using 语法糖会产生 try/finally 块
SqlConnection myConnection = null; // Example Using clause: using (myConnection = new SqlConnection(connString)) { myConnection.Open(); } // 等价于 // example Try / Catch block: try { myConnection = new SqlConnection(connString); myConnection.Open(); } finally { myConnection.Dispose(); }
快速保护方法 是使用 as 语句可以转换为安全可回收对象不管是否实现 IDisposable 接口
- using 语句对在编译时期类型实现 IDisposable 接口才能正常工作
// Does not compile. 编译报错// Object does not support IDisposable.using (object obj = Factory.CreateResource()) { Console.WriteLine(obj.ToString());}
- 快速保护方法
// The correct fix.// Object may or may not support IDisposable.object obj = Factory.CreateResource();using (obj as IDisposable) { //如果 obj 没有实现 IDisposable 接口,则这行代码 等价于 using(null) { Console.WriteLine(obj.ToString());}
字符串拼接
- 使用 sting.Format 或者 StringBuilder 替代 string 的 += 拼接操作
- StringBuilder 类似 Vector 一样是动态扩容。
限制你的类型的可见性
- 尽可能的减少类的可见性,例如某些类里需要一些数据结构类,应该设为 private 或 这 internal ,不让外部知道
让接口支持协变和逆变
让接口支持 逆变、协变,限制 泛型只能是参数 或者 只能是返回值,例如Action 和 Func 这两个委托,这个有点抽象
public interface IMyList2<out T> { T GetElement(); //void ChangeT(T t); // 这里编译错误,因为 T 被 out 修饰,所以 T 只能做返回值,不能做参数 } public class MyList2<T> : IMyList2<T> { public T GetElement() { return default(T); } public void ChangeT(T t) { //Change T } } //------------------------------- public interface IMyList<in T> { //T GetElement(); // 这里编译错误,因为 T 被 in 修饰,所以 T 只能做参数,不能做返回值 void ChangeT(T t); } //没有指定 in 或者 out,就可以即做 参数 又做 返回值 public class MyList<T> : IMyList<T> { public T GetElement() { return default(T); } public void ChangeT(T t) { //Change T } }
上面这些是个人感觉比较能用到的东西
- 阅读笔记_《effective-csharp》
- 《Effective C++》阅读笔记
- Effective C++阅读笔记
- effective stl 阅读笔记
- 《Effective C++》阅读笔记
- Effective Java 阅读笔记
- Effective C++ 阅读笔记
- Effective Java阅读笔记
- more effective C++阅读笔记
- More Effective C++ 阅读笔记
- effective C++ 阅读笔记 1
- effective C++ 阅读笔记 2
- effective C++阅读笔记 3
- effective C++ 阅读笔记 4
- 《Effective C++》阅读笔记01
- 《Effective C++》阅读笔记02
- 《Effective C++》阅读笔记03
- Effective c++ 阅读笔记1
- java代码实现打印菱形
- Pycharm连接Oracle数据库
- 在 Android Native 程序中输出 LOG
- sql:常用sql语句整理二 (连接查询)
- 使用Thrift的网络框架搭建一般性网络应用
- 阅读笔记_《effective-csharp》
- Python MySQLdb连接数据库的应用
- iOS 10 的适配问题
- 理论---<url pattern> 匹配规则
- HashMap中key为null时存到哪里去了
- 勒索病毒防护方案
- Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析
- WebView使用详解
- 修改VS2008(vc)中工程/解决方案/类的名字