一、 使用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; }
}

运行结果如下

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

引用类型则相反。

C#高效编程的更多相关文章

  1. C# 高效编程笔记2

    C# 高效编程笔记2 1.理解GetHashCode()的陷阱 (1)作用:作为基于散列集合定义键的散列值,如:HashSet<T>,Dictionary<K,V>容器等 (2 ...

  2. C# 高效编程笔记1

    C# 高效编程笔记1 1.使用属性而不是可访问的数据成员 (1).NET Framework中的数据绑定类仅支持属性,而不支持共有数据成员 (2)属性相比数据成员更容易修改 2.用运行时常量(read ...

  3. Python高效编程的19个技巧

    初识Python语言,觉得python满足了我上学时候对编程语言的所有要求.python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c++的人,兴奋的不行不行的,终于解脱了.高级语言,如果做 ...

  4. 架构师速成-如何高效编程 for java

    引子 赵云大喝一声,挺枪骤马杀入重围,左冲右突,如入无人之境.那枪浑身上下,若舞梨花:遍体纷纷,如飘瑞雪. 赵云是所有历史人物中我最喜欢的一个,如果放到现代,他走了it的道路,一定可以成为一个编程高手 ...

  5. C语言高效编程的几招(绝对实用,绝对经典)

    编写高效简洁的C语言代码,是许多软件工程师追求的目标.废话不说,走起! 第一招:以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题 eg.字符串的 ...

  6. [收藏转贴]struct探索·extern "C"含义探索 ·C++与C的混合编程·C 语言高效编程的几招

    一.C/C++语言 struct深层探索 1.自然对界 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如 int.long.float等)的变量,也可以是一些复合数据类型(如 arr ...

  7. [.NET] 《C# 高效编程》(一) - C# 语言习惯

    C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Con ...

  8. [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充

    <Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...

  9. 【Matlab编程】Matlab高效编程技巧

    1.默认状态下,matlab显示精度是short型,而默认的计算精度是double型,并且显示精度与计算精度没有关系. 2. 一只失明的猫的问题:注意方法! 3.给数组预分配空间是基本的高效编程准则之 ...

  10. 18个Python高效编程技巧,Mark!

    初识Python语言,觉得python满足了我上学时候对编程语言的所有要求.python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c++的人,兴奋的不行不行的,终于解脱了.高级语言,如果做 ...

随机推荐

  1. ansible-playbook-常用

    创建软链:file: - name: create link hosts: "{{hosts_ip}}" tasks: - name: create link file: src= ...

  2. 声源定位之2精读《sound localization based on phase difference enhancement using deep neuarl networks》

    2.1.1 题目与摘要 1.为什么要增强IPD? The phase differences between the discrete Fourier transform (DFT) coeffici ...

  3. VS Code中python代码自动格式化 代码自动检查

    VS Code菜单栏中依次打开 File—Preferences—Settings,搜索框中搜索“python.formatting.provider”, 然后在下拉菜单中选择autopep8,yap ...

  4. 讨厌的linux----vsftpd 匿名上传配置

    核心一句话: vsftpd: refusing to run with writable anonymous root 匿名账号的根目录,不允许写入,否则匿名登录 验证失败 只有再 ftp 命令操作, ...

  5. Spring Cloud上下文:应用程序上下文服务

    Spring Boot对于如何使用Spring构建应用程序有一个看法:例如它具有常规配置文件的常规位置,以及用于常见管理和监视任务的端点.Spring Cloud建立在此之上,并添加了一些可能系统中所 ...

  6. pip安装daemon模块

    E:\> pip install python-daemon Collecting python-daemon Downloading https://files.pythonhosted.or ...

  7. Laravel 控制器 Controller

    一.控制器存在的意义 路由可以分发请求:路由中还可以引入 html 页面:我们可以在 route/web.php 中搞定一切了:但是如果把业务逻辑都写入到路由中:那路由将庞大的难以维护:于是控制器就有 ...

  8. Linux内核链表——看这一篇文章就够了

    本文从最基本的内核链表出发,引出初始化INIT_LIST_HEAD函数,然后介绍list_add,通过改变链表位置的问题引出list_for_each函数,然后为了获取容器结构地址,引出offseto ...

  9. Js设置打印缩放

    近期需要优化一个打印项目,因为是固定长度,所以需要缩放打印,记录一下 //获取打印的页面内容 let subOutputRankPrint = document.getElementById('pri ...

  10. java多线程(四)死锁

    1.1. 什么是死锁 多线程以及多进程改善了系统资源的利用率并提高了系统的处理能力.然而,并发执行也带来了新的问题--死锁. 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用, ...