1、开发者把更多注意力集中在名称上,而不用分心去考虑类型
2、编译器选取的类型可能比开发者指定的合适:如IQueryable和IEnumerable
3、变量是值类型,不建议var,可能产生以下问题
(1)宽化转换,比较安全,比如float到double
(2)窄化转换:会令精度下降,比如long到int
1、const:编译器期量,使用它的地方,在编译时会变成a=1,若常量发生变更而不重新编译,会不生效;readonly:运行期常量,赋值更灵活
2、const性能比readonly好
3、const可能存在的问题:若A程序集引用了B程序集的常量,B程序集修改了常量的值,A程序集没有进行重新生成,则A程序的常量值还是B程序集的旧值
1、C# 6.0 提供
2、可读性更好
3、避免序号与数组位置不对应或数量不相等导致的bug
4、不会创建参数化SQL查询,SQL语句需注意
用nameof运算符来写代码的好处是:
如果属性名变了,那么用来构造PropertyChangedEventArgs对象的参数也随之变化。
例如:线程安全调用 event?.Invoke();
1、装箱是将值类型转换成引用类型
2、取消装箱是把已经装箱的那个值拷贝出来
3、拆箱是将引用类型转换成值类型,只有装箱过的对象才能拆箱
设置虚方法就是告诉使用者派生类可能以其他方式实现这个虚方法
1、垃圾回收器GC
(1)使开发者无需担心内存泄漏、迷途指针、未初始化的指针以及其他内存管理问题
(2)非托管资源需要开发者自己控制,如数据库连接、GDI+对象、COM对象等
2、两种控制非托管资源机制
(1)finalizer:防护机制,可以确保对象总是能够把非托管资源释放掉,但缺陷很多
(2)IDsposable接口,推荐使用
1、如果初始化开销比较大或复杂,可以考虑运用Lazy机制
2、如无多态,可在静态构造函数中实现单例
可以考虑带默认值的构造函数还是多个互相重载的构造函数
这章节里的大多数篇幅比较常,代码量较多,就不多解释,有兴趣的可以去深入了解下。
这章节里的大多数篇幅比较常,代码量较多,就不多解释,有兴趣的可以去深入了解下。
我个人是觉得用循环可能好点,比较直观,一眼就知道代码是干嘛了,虽然查询语句也不差。
// 使用循环
var list1 = new List<int>();
foreach (var item in Enumerable.Range(0, 100))
{
list1.Add(item * item);
}
foreach (var item in list1)
{
Console.WriteLine(item);
}
// 使用查询语句
var list2 = (from n in Enumerable.Range(0, 100)
select n * n).ToList();
list2.ForEach(n => Console.WriteLine(n));
有点像AOP切面编程
只有当程序确实要用到某个方法的执行结果时,才会去调用这个方法。
这就是声明式写法和命令式写法的重要区别。
令代码在发生异常时依然能保持稳定是每一位C#程序员所应掌握的关键技能。
1、如果方法不能够完成其所宣称的操作,那么应该通过异常来指出这个错误,如果改用错误码来实现,那么这些代码,容易被调用方所忽视。
2、错误码必须由调用方来处理,而异常则可以验证调用栈向上传播,直至到合适的catch子句。
如果某个类型用到了非托管的系统资源,如File,那么就需要通过IDsposable接口的Dispose方法来明确的释放。
而想要确保方法总是能够得到调用,最好的办法就是利用using语句或者try/finally语句块。
采用异常筛选器会给程序性能带来正面影响。.NET CLR对带有when关键字的try/catch结构做了优化,
使得程序在无须进入该结构时其性能尽量不会受到影响。
如下,捕捉异常后,保存日志后继续抛出:
// SaveLog返回false
// 不使用筛选器
try
{
try
{
Convert.ToInt32("w");
}
catch (Exception ex)
{
SaveLog(ex);
throw;
}
}
catch { }
// 使用筛选器
try
{
try
{
Convert.ToInt32("w");
}
catch (Exception ex) when (SaveLog(ex))
{
}
}
catch { }