c# 编码优秀习惯
文章平均质量分 62
职位不代表优秀,经验也不代表优秀,吹牛皮更不代表优秀,真正的优秀是有一个良好的编码习惯。
喵叔哟
一个关注AI和Java的.NET程序员
展开
-
利用 IComparable<T> 以及 IComparer<T> 定义顺序关系
我们都知道,在开发中如果想把某个类型的对象放入集合中执行排序和搜索功能,就需要定义出来对象与对象之间的关系。那么你知道怎么样定义对象关系才是正确的吗?下面就听我一一道来。零、讲解在 .NET 中有两个接口可以用来定义关系,即 IComparable 和 IComparer 。前者用来规定某类型的给对象之间所具备的自然顺序,后者用来表示另一种排序机制可以有需要提供排序功能的类型来实现。 IComparable 接口只有一个方法 CompareTo ,该方法遵循如下的惯例:如果本对象小于另一个受测对象,就返原创 2020-11-09 23:37:14 · 411 阅读 · 0 评论 -
使用null条件运算符调用事件处理程序
对于刚接触事件处理的开发人员来说,会觉得触发事件是一个非常容易的事情,只需要把事件定义好在触发的时候调用相关事件就可以了。但是实际上触发事件不是那么的简单,我们在这里考虑两个问题:如果在程序中根本没有任何一个处理程序和某个事件关联,会出现什么情况?如果存在多个线程都要检测并调用同一个事件,这些线程之间又存在争夺的问题,会出现什么情况?针对上面这两个问题,在 C# 6.0 中新增的 null 条件运算符就可以解决这个问题。下面我们先来看一下简单的代码段。//不安全的方式public class原创 2020-07-19 21:21:56 · 388 阅读 · 0 评论 -
通过运行期类型检查实现泛型算法
Tip:本文首发于喵叔的 CSDN 博客,转载于喵叔的 InfoQ 博客,本人未授权任何网站、公众号以及其他任何形式的转载。发布不等于免费、开源不等于无所顾忌,请遵守职业道德。零、第一次优化虽然我们可以通过指定不同的类型参数来实现泛型类的复用,但是在某些情况下通用就意味着我们无法利用具体类型的优势。针对这一点 C# 允许在发现类型参数所表示的对象具有更多的功能时编写更具体的代码。这一点是利...原创 2020-04-25 13:46:19 · 893 阅读 · 0 评论 -
规范约束条件
我们在开发时往往会对泛型指定约束条件,只有类型参数符合条件的才允许用在这个泛型上面。但是有时我们会定义过多或过少的约束条件,过多的约束条件会导致其他开发人员在使用你所编写的方法或类时做很多的工作以满足这些约束,过少的约束又会导致程序在运行的时候必须做很多的检查,并执行更多的强制类型转化操作,有时我们还需要使用反射生成运行期错误,来防止用户误用这个类。要解决这些问题,我们就必须把确实需要的约束写出来...原创 2020-04-21 22:51:21 · 1298 阅读 · 0 评论 -
如何实现标准的dispose
前面的文章我们说过,如果对象包含非托管资源那么就必须要正确的清理,现在我们就来说一下如何清理。针对非托管资源 .NET 会采用一套标准的模式来完成清理工作。也就是说如果开发人员自己编写的类中存在非托管资源,那么这个类的使用者就会认为这个类遵循 .NET 的垃圾清理模式。标准的 dispose 模式即实现了 IDisposable 接口,又实现了 finalizer ,这样就可以在客户端忘记调用 I...原创 2020-04-18 11:09:28 · 636 阅读 · 0 评论 -
禁止在构造函数里调用虚函数
在构造函数中调用虚函数会导致程序出现莫名其妙的行为,这主要是对象还没有完全构造完成。下面我们先来看一段代码:class B{ protected B() { Method(); } protected virtual void Method() { Console.WriteLine("B Method"); }...原创 2020-04-16 23:01:04 · 530 阅读 · 0 评论 -
抛弃无所谓的对象
虽然 GC 可以帮助我们很好的管理内存,并且高效的将用不到的对象清理出去,但是这并不意味着我们可以随意创建对象。尤其是在方法中创建很多局部引用对象很有可能会降低程序的性能。 GC 的执行时机与程序所分配的内存数量以及分配的频率有关系,如果总是分配内存就会给 GC 造成很大的压力,从而使得 GC 会运行的很频繁进而降低了程序的性能。一般来说我们会将实现了 IDisposable 接口的类型中的变量提...原创 2020-04-14 22:52:23 · 430 阅读 · 0 评论 -
整合重复的初始化逻辑
我们在开发中会在一个类中定义不同版本的构造函数,这些构造函数往往存在相同的初始化逻辑。遇到这种情况一部分开发人员会在每个构造函数中编写相同的代码,这种编写代码的方式是比较低级的,正确的做法应该是将相同的初始化逻辑提取到一个公用的构造函数中,并让其他构造函数直接或间接的调用。这样既可以减少重复的代码,又可以使得编译器根据初始化命令生成更高效的目标代码。下面我们就根据上面所说的内容来编写一下代码。p...原创 2020-04-12 19:44:04 · 350 阅读 · 0 评论 -
确保初始化静态成员
在开发时我们习惯在创将某个实例之前先把静态成员变量初始化好,具体做法是通过静态初始化语句以及静态构造函数。静态构造函数在 c# 是比较特殊的函数,它会在第一次访问所在类定义的其他方法、变量和属性之前执行,一般我们用它来初始化静态变量、实现单例模式以及执行其他一些需要在访问其他必要的工作。如果静态字段初始化工作较为复杂或者是初始化开销很大的话,那么我们可以使用 Lazy 机制将初始化工作推迟在第一次...原创 2020-04-12 16:23:21 · 394 阅读 · 0 评论 -
为字段设置初始值
在开发中为字段设置初始值这是最基本的要求,但是很多开发人员会在构造函数变多的时候忘记给成员变量设置初始值。为了避免这个问题,我们最好在声明的时候直接初始化,而不是在实现构造函数的时候去初始化。编译器会帮助开发人员在每个构造函数开头放入一段代码,这段代码会把开发人员在定义成员字段时所指定的初始值设置给这些成员字段。如果没有显示定义构造函数,那么编译器就会先创建默认构造函数,之后再向其中加入初始化代码...原创 2020-04-11 01:18:14 · 2021 阅读 · 0 评论 -
闲话资源管理
对于 .NET 开发人员来说程序的资源管理是必不可少的,要开发出一款优秀的应用就必须明白 .NET 的资源管理机制。在 .NET 中垃圾回收器 GC 帮助我们管理托管资源,在开发时我们不需要过多的关注大多数内存问题(例如:内存泄漏、dangling pointer)。零、托管资源在 .NET 中一个经典的资源管理的例子就是 GC 对循环引用的管理。 GC 的 Mark and Compact ...原创 2020-04-09 00:34:38 · 261 阅读 · 0 评论 -
正确使用 new 修饰符
几乎 .NET 所有开发人员都知道 new 修饰符可以重新定义从基类中继承的非虚成员,但是大部分开发人员并不知道怎么才能正确使用,甚至出现了滥用的情况。零、纠正常犯错误讲解如何正确使用 new 修饰符前我们先来看一个段代码。public class DemoBase{ public void Method() { Console.WriteLine("Hel...原创 2020-04-06 16:32:56 · 689 阅读 · 0 评论 -
减少装箱与拆箱
在 .NET 中存在一个的冲突,值类型不应该被设计为多态类型,但是 .NET Framework 又必须把 System.Object 设计为引用类型,并把它作为整个对象体系的基础。针对这一冲突 .NET 引入了装箱与拆箱。所谓的装箱就是把值类型放在非类型化的引用对象中,使得需要使用引用类型的地方也可以使用值类型,而拆箱指的是把已经装箱的值复制出来一份。在只能使用 System.Object 类型...原创 2020-04-05 20:09:05 · 1325 阅读 · 0 评论 -
正确调用事件处理程序
不管是刚接触 C# 还是已经具有多年开发经验的大部分人会觉得事件处理很简单,只需要把事件定义好然后在需要的时候出发它就可以了。其实这种想法是错误的,这里面有很多需要注意的问题。下面这段代码是大部分开发人员经常使用的定义事件处理程序的方法。public class EventDemo{ private EventHandler<int> demo; public vo...原创 2020-03-29 11:06:20 · 484 阅读 · 0 评论 -
优先考虑 nameof
在分布式场景中,我们经常需要进行多个系统之间的通信,要实现这些通信往往需要不同的库对相应的需求进行处理。这些库为了实现跨平台和跨语言的兼容性往往利用数据名称和字符串来运行,但是这么做就会出现类型安全问题,并且大部分工具也无法支持。针对前面所述的问题, C# 6.0 中新增了 nameof 表达式,这个表达式可以根据变量来获取包含其名称的字符串,从而使开发人员不需要将变量名称写成字符串。使用 na...原创 2020-03-10 23:34:44 · 1168 阅读 · 0 评论 -
FormattableString 取代特定区域字符串
有些软件系统是针对全球来开发的,因此一些字符串需要根据不同地区不同语言做出特定的处理。如果针对不同地区不同用语言分别编写字符串处理方法的话代码量是巨大的。那么这个时候我们可以用到内插字符串深层的特性,C# 会把内插字符串的结果隐式的转换成 string 或者 FormattableString 。例如下面这个例子,内插字符串的结果将是 string 类型:string message = $"...原创 2020-03-07 13:20:11 · 3285 阅读 · 0 评论 -
少用 string.Format
如果你使用的是 C# 6.0 及其以上版本的话我建议你使用新增的 内插字符串 这个功能。这个功能可以更好的帮助开发人员设置字符串格式。下面我们就来看一下为什么要少用 string.Format 而要多用内插字符串,以及内插字符串的优缺点。String.Format 在 C# 6.0 以前我们会经常用到这个,优点在这里我就不一一阐述了,这里我们主要说一下它的缺点。开发人员必须对生成的字符串进行...原创 2020-03-01 13:20:35 · 815 阅读 · 0 评论 -
多用as少用强制类型转换
在 C# 中存在一个名叫静态类型检查的机制,这个机制可以让编译器帮助我们把类型不服的用法找出来,从而使得应用程序在运行期间加少一些类型检查的操作。但是有时候我们还是需要进行运行期类型检查,比如我们在设计框架时将方法的参数类型定义为 object ,那么这时我们就有很大的可能需要将 object 类型的参数先转换为其他类型。我们进行转换时会有两种方法可以使用:一种是强制类型转换,这种方法可以绕过编译...原创 2020-02-18 19:22:26 · 1752 阅读 · 0 评论 -
巧用 readonly与 const
c# 中的常量有两种,分别是编译期常量和运行期常量。通过名字我们就可以看出来它俩在行为上是不同的。在开发中如果这两种常量选择的不合适,就会影响到程序的开发工作以及程序的性能。下面我们先来看一下运行期常量和编译期常量的定义方法。零、定义运行期常量我们使用 readonly 来定义,而编译器常量我们使用 const 来定义。// 运行期常量public static readonly stri...原创 2020-02-01 13:03:49 · 2292 阅读 · 0 评论 -
var lady first
C# 中的隐式类型的局部变量是为了支持匿名类型而出现的,并且也是为了解决一部分查询操作返回的结果是 IQueryable 类型,而另一部分查询返回的结果是 IEnumerable 类型导致的把 IQueryable 当作 IEnumerable 来使用,进而无法使用 IQueryProvider 提供的增强功能。在这里一定会有读者担心如果没有把变量的类型写明是不是会造成类型安全问题。那么,在这里我...原创 2020-01-14 00:16:41 · 1765 阅读 · 0 评论