C#高效编程
一、 使用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#高效编程的更多相关文章
- C# 高效编程笔记2
C# 高效编程笔记2 1.理解GetHashCode()的陷阱 (1)作用:作为基于散列集合定义键的散列值,如:HashSet<T>,Dictionary<K,V>容器等 (2 ...
- C# 高效编程笔记1
C# 高效编程笔记1 1.使用属性而不是可访问的数据成员 (1).NET Framework中的数据绑定类仅支持属性,而不支持共有数据成员 (2)属性相比数据成员更容易修改 2.用运行时常量(read ...
- Python高效编程的19个技巧
初识Python语言,觉得python满足了我上学时候对编程语言的所有要求.python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c++的人,兴奋的不行不行的,终于解脱了.高级语言,如果做 ...
- 架构师速成-如何高效编程 for java
引子 赵云大喝一声,挺枪骤马杀入重围,左冲右突,如入无人之境.那枪浑身上下,若舞梨花:遍体纷纷,如飘瑞雪. 赵云是所有历史人物中我最喜欢的一个,如果放到现代,他走了it的道路,一定可以成为一个编程高手 ...
- C语言高效编程的几招(绝对实用,绝对经典)
编写高效简洁的C语言代码,是许多软件工程师追求的目标.废话不说,走起! 第一招:以空间换时间 计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题 eg.字符串的 ...
- [收藏转贴]struct探索·extern "C"含义探索 ·C++与C的混合编程·C 语言高效编程的几招
一.C/C++语言 struct深层探索 1.自然对界 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如 int.long.float等)的变量,也可以是一些复合数据类型(如 arr ...
- [.NET] 《C# 高效编程》(一) - C# 语言习惯
C# 语言习惯 目录 一.使用属性而不是可访问的数据成员 二.使用运行时常量(readonly)而不是编译时常量(const) 三.推荐使用 is 或 as 操作符而不是强制类型转换 四.使用 Con ...
- [.NET] 《Effective C#》快速笔记 - C# 高效编程要点补充
<Effective C#>快速笔记 - C# 高效编程要点补充 目录 四十五.尽量减少装箱拆箱 四十六.为应用程序创建专门的异常类 四十七.使用强异常安全保证 四十八.尽量使用安全的代码 ...
- 【Matlab编程】Matlab高效编程技巧
1.默认状态下,matlab显示精度是short型,而默认的计算精度是double型,并且显示精度与计算精度没有关系. 2. 一只失明的猫的问题:注意方法! 3.给数组预分配空间是基本的高效编程准则之 ...
- 18个Python高效编程技巧,Mark!
初识Python语言,觉得python满足了我上学时候对编程语言的所有要求.python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c++的人,兴奋的不行不行的,终于解脱了.高级语言,如果做 ...
随机推荐
- ansible-playbook-常用
创建软链:file: - name: create link hosts: "{{hosts_ip}}" tasks: - name: create link file: src= ...
- SEAndroid
SEAndroid安全机制所要保护的对象是系统中的资源,这些资源分布在各个子系统中,例如我们经常接触的文件就是分布文件子系统中的. 实际上,系统中需要保护的资源非常多,除了前面说的文件之外,还有进程. ...
- 把ngnix注册为linux服务 将Nginx设置为linux下的服务 并设置nginx开机启动
一.创建服务脚本 vim /etc/init.d/nginx 脚本内容如下 #! /bin/sh# chkconfig: - 85 15 PATH=/usr/local/nginx/sbin/ DES ...
- linux安装chrome及chromedriver(转)
1.chrome: curl https://intoli.com/install-google-chrome.sh | bash 1.1.centos安装chrome: 從 Google 下載最新版 ...
- grpc使用记录(一) gRPC编译(mscv/gcc)
目录 1.编译前的准备工作 2.Windows下使用VS2019编译 2.1.使用cmake生成VS2019解决方案 2.2.使用msbuild工具进行编译 3.linux下编译 3.1 CentO ...
- i系列标准-互联网周刊
原文:http://www.enet.com.cn/article/2019/0429/A20190429062899.html 传统意义上的规模.现代意义上的工具时代感.永远不会改变的最高意义上的使 ...
- tomcat安全基线
为了符合tomcat安全基线,需要做一下加固: 1.管理用户的密码加密:<摘要算法加密tomcat登录密码> 管理用户在conf/tomcat-users.xml中配置,密码一般是明文形式 ...
- Web API之Web Components
本文参考<你的前端框架要被web组件替代了>. 于2011年面世的Web Components是一套功能组件,让开发者可以使用 HTML.CSS 和 JavaScript 创建可复用的组件 ...
- python结巴分词SEO的应用详解
结巴分词在SEO中可以应用于分析/提取文章关键词.关键词归类.标题重写.文章伪原创等等方面,用处非常多. 具体结巴分词项目:https://github.com/fxsjy/jieba ...
- proc 下创建与应用交互的可读写节点
内核版本:Linux-4.14 随便写了个 proc 下节点的测试程序,可以用来与应用层交互. 也可以单独的用来做调试打印使用,例如封装个 my_printk 将信息单独存在节点内,然后可以在应用层 ...