一、 使用readonly而不是const

const是编译时常量,readonly是运行时常量。如果引用了一个库中的const常量,则在更新了程序集,但应用程序没有重新编译时,运行结果会出错

如程序集assembly.dll中有如下声明

 public static readonly int Start = ;
public const int End = ;

在ConsoleApp.exe中调用。在正常编译的情况下是没有问题的,但如果更新了assembly.dll中的声明,却不重新编译ConsoleApp.exe,此时End常量的值依旧是10

 public static readonly int Start = ;
public const int End = ;

二、使用is和as关键字,而不是使用强制类型转换

强制类型转换不当会引发 InvalidCastException异常。使用is和as可以避免这个问题

三、使用$ - 字符串内插来格式化字符串,而不是string.Format()函数.这个功能需要C#6.0

https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/interpolated

四、尽量使用Conditional特性,减少#if和#endif的使用

平常我们会使用#if和#endif来执行一些Debug环境下执行的代码。这些代码在编译成Release版本时不会执行,但仍然会有一些开销。这时我们就可以使用Conditional特性,使用了Conditional特性的函数只有在某些环境或者设置了某个值之后才能编译成类的一部分,这样就可以减少Release版本的开销。值得注意的,使用Conditional特性必须把以前的调试部分代码封装成函数才行。

需要了解ConditionalAttribute更详细的说明,可以查看MSDN文档 https://docs.microsoft.com/zh-cn/dotnet/api/system.diagnostics.conditionalattribute?redirectedfrom=MSDN&view=netframework-4.8

使用#if和#endif的情况

当定义了DEBUG符号时,控制台会输出Debug和Release。未定义DEBUG符号时,只会输出Release。

 #define DEBUG

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
#if DEBUG
Console.WriteLine("Debug");
#endif
Console.WriteLine("Release"); } }
}

使用Conditional特性的情况

输出情况是跟上面一致的。但当未定义DEBUG符号时,DebugMethod不会被编译进MSIL。可以节省开销

值得注意的是,应用了Conditional特性的函数,返回类型只能为void

 #define DEBUG

 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
DebugMethod(); Console.WriteLine("Release");
} [Conditional("DEBUG")]
static void DebugMethod()
{
Console.WriteLine("Debug");
} }
}

五、如何正确的对成员变量进行初始化(这个问题困扰了我好久,今天终于有解决方案了)

大多情况下,使用成员初始化器对成员进行初始化。

就是在声明时就进行初始化,而不是放到构造函数。初始化器可以看做是构造函数中初始化语句的另一种表示。初始化器生成的代码会在构造函数前执行。如果是派生类,初始化器会在父类的构造函数前执行,然后再执行子类的构造函数。

public class Patient
{
List<Bitmap> images = new List<Bitmap>();
string patientName;
int patientId; public Patient()
{ }
}

下面三种情况,不推荐使用初始化器语法

1、值类型初始值设为0,引用类型初始值设为null的情况

系统默认的初始化工作将在所有代码执行之前把一切都设置成0或null。系统生成0或者null的这一步操作是位于很底层的实现,会直接使用CPU指令将一整块内存设置为0。

所以以下代码是多余的

 int num = ;
Student stu = null;

2、需要对这个变量执行不同的初始化方式的情况。初始化器语法的前提是,所有的构造函数都会将变量设置为同样的值。

3、在进行初始化时,可能会引发异常的情况。这种情况下,就需要在构造函数中进行初始化,以便进行相应处理。

六、区分值类型和引用类型

值类型应该是那些小型、轻量级的类型,分配在栈上

引用类型则用来构成类层次结构,分配在堆上。

有如下代码

 MyType[] arrayOfTypes = new MyType[];

如果MyType属于值类型,那么将一次分配大小为MyType的100倍空间

如果MyType属于引用类型,那么也仅会分配一次,数组中的每个元素都为空。在初始化数组中的元素时,将执行101次分配,101次分配要比1次分配更占用时间,分配大量的引用 类型将让堆上充满碎片。

还有一点值得注意的是,在集合中查找元素时,如果集合里是值类型,则查找出来的元素跟集合中的元素是不同的引用。如果是引用类型,则查找出来的元素跟集合中的该元素是相同的引用。在修改值的时候,会导致意外的发生。

有如下代码

 class Program
{
static void Main(string[] args)
{
Test1 test1 = new Test1() { Name = "Test1"};
Test2 test2 = new Test2() { Name = "Test2"}; List<Test1> list1 = new List<Test1>() { test1 };
var temp1 = list1.Find(x => x.Name == "Test1");
Console.WriteLine(object.ReferenceEquals(test1,temp1)); temp1.Name = "Modified Test1";
Console.WriteLine(list1.ElementAt().Name); List<Test2> list2 = new List<Test2>() { test2 };
var temp2 = list2.Find(x => x.Name == "Test2");
Console.WriteLine(object.ReferenceEquals(test2,temp2)); temp2.Name = "Modified Test2";
Console.WriteLine(list2.ElementAt().Name); }
} struct Test1
{
public string Name { get; set; }
} class Test2
{
public string Name { get; set; }
}

运行结果如下

可以看到,查找出来的值类型集合中的元素,跟添加时的元素并不是同一个引用,而且修改值,也不会导致集合中元素的更改。

引用类型则相反。

最新文章

  1. 从网上找的 visual studio 的各个版本下载地址,vs2010/vs2012/vs2013带注册码
  2. phpstorm version 2016.2 License Server激活
  3. ASP.NET Core 开发 - Entity Framework (EF) Core
  4. HttpSession的线程安全问题及注意事项
  5. Error applying BeanValidation relational constraints 错误解决
  6. mplayer-for-windows change color scheme in win 7
  7. PySide 简易教程&lt;三&gt;-------动手写起来
  8. Adb工具常用操作(一)
  9. 轻松解决ubuntu系统引导问题
  10. 使用iframe从网页调起移动端应用
  11. voa 2015 / 4 / 15
  12. php面试题汇总一(基础篇附答案)
  13. .net ef core 领域设计代码转换(上篇)
  14. freemarker报错之十
  15. JS-JAVASCRIPT的eval()方法
  16. Flex核心属性整理
  17. day12 Python数字,字符串,列表,元祖,字典总结
  18. 大数据-07-Spark之流数据
  19. hybrid项目h5页路由回退问题解决
  20. xshell5不能用

热门文章

  1. 理解Docker :Docker 网络
  2. 有关于服务端模板注入(ssti攻击)——BUUCTF - easy_tornado
  3. Json文件的BOM
  4. Excel多表头设置二级联动选择
  5. 冰多多团队-第一次Scrum例会
  6. poi导出word表格跨行
  7. nohup: 无法运行命令&quot;java&quot;: 没有那个文件或目录
  8. C++ 已知两个时间(年月日)求日期差
  9. Generate a Certificate Signing Request (CSR) in macOS Keychain Access
  10. 小于K的两数之和