UnityEffective C#观后感之提高Unity中C#代码质量的21条准则

Posted 天生爱赞美

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UnityEffective C#观后感之提高Unity中C#代码质量的21条准则相关的知识,希望对你有一定的参考价值。

我们知道,在C++领域,作为进阶阅读材料,必看的书是《Effective C++》。 而《Effective C#》之于C# ,是类似《Effective C++》之于C++一样的存在。

这篇文章,将《Effective C# Second Edition》一书中适用于Unity游戏引擎里使用C#的经验之谈进行了提炼,总结成为21条(一开始总结的是22条,后来发现第22条也是.NET的特性,Unity版本的mono并没有实现,所以严格意义上来说是21条)准则,供各位快速地掌握这本书的知识梗概,在Unity中写出更高质量的C#代码。


《Effective C# Second Edition》一书原本有50条原则,但这50条原则是针对C#语言本身以及.NET来写的,我在阅读过程中,发现是有些原则并不适用于Unity中mono版本的C#的使用。于是,在进行读书笔记总结的时候,将不适用的原则略去,同时将适用的原则进行提炼,总结出21条,构成本文的内容。


需要注意,因为是挑出了书中适用的准则,导致准则序号有些跳跃,为了阅读方便,本文对这些序号进行了重新排列。重排后,标题中与书中序号不一样的准则,都在该原则总结的末尾注明了对应的原书序号。


同样地,作为总结式文章,每一条的内容都高度概括,也许理解坡度比较陡,若有读到不太理解的地方,建议大家去阅读原书,英文版和中文版均可,看看原书中提供的各种代码与示例,这样掌握起来就会事半功倍。


本文内容思维导图式总结

以下是本文内容,提高Unity中C#代码质量的22条准则的总结式思维导图


原则1

尽可能地使用属性而不是可直接访问的数据成员

       

● 属性(property)一直是C#语言中比较有特点的存在。属性允许将数据成员作为共有接口的一部分暴露出去,同时仍旧提供面向对象环境下所需的封装。属性这个语言元素可以让你像访问数据成员一样使用,但其底层依旧是使用方法实现的。


● 使用属性,可以非常轻松的在get和set代码段中加入检查机制。


需要注意,正因为属性是用方法实现的,所以它拥有方法所拥有的一切语言特性:

1)属性增加多线程的支持是非常方便的。你可以加强 get 和 set 访问器(accessors)的实现来提供数据访问的同步。

2)属性可以被定义为virtual。

3)可以把属性扩展为abstract。

4)可以使用泛型版本的属性类型。

5)属性也可以定义为接口。

6)因为实现实现访问的方法get与set是独立的两个方法,在C# 2.0之后,你可以给它们定义不同的访问权限,来更好的控制类成员的可见性。

7)而为了和多维数组保持一致,我们可以创建多维索引器,在不同的维度上使用相同或不同类型。


无论何时,需要在类型的公有或保护接口中暴露数据,都应该使用属性。如果可以也应该使用索引器来暴露序列或字典。现在多投入一点时间使用属性,换来的是今后维护时的更加游刃有余。


原则2

偏向于使用运行时常量而不是编译时常量

       

对于常量,C#里有两个不同的版本:运行时常量(readonly)和编译时常量(const)。


应该尽量使用运行时常量,而不是编译器常量。虽然编译器常量略快,但并没有运行时常量那么灵活。应仅仅在那些性能异常敏感,且常量的值在各个版本之间绝对不会变化时,再使用编译时常量。


编译时常量与运行时常量不同之处表现在于他们的访问方式不同,因为Readonly值是运行时解析的:

● 编译时常量(const)的值会被目标代码中的值直接取代。

● 运行时常量(readonly)的值是在运行时进行求值。● 引用运行时生成的IL将引用到readonly变量,而不是变量的值。


这个差别就带来了如下规则:

● 编译时常量(const)仅能用于数值和字符串。

● 运行时常量(readonly)可以为任意类型。运行时常量必须在构造函数或初始化器中初始化,因为在构造函数执行后不能再被修改。你可以让某个readonly值为一个DataTime结构,而不能指定某个const为DataTIme。

● 可以用readonly值保存实例常量,为类的每个实例存放不同的值。而编译时常量就是静态的常量。

● 有时候你需要让某个值在编译时才确定,就最好是使用运行时常量(readonly)。

● 标记版本号的值就应该使用运行时常量,因为它的值会随着每个不同版本的发布而改变。

● const优于readonly的地方仅仅是性能,使用已知的常量值要比访问readonly值略高一点,不过这其中的效率提升,可以说是微乎其微的。


综上,在编译器必须得到确定数值时,一定要使用const。例如特性(attribute)的参数和枚举的定义,还有那些在各个版本发布之间不会变化的值。除此之外的所有情况,都应尽量选择更加灵活的readonly常量。


原则3

推荐使用is 或as操作符而不是强制类型转换

            

● C#中,is和as操作符的用法概括如下:

is : 检查一个对象是否兼容于其他指定的类型,并返回一个Bool值,永远不会抛出异常。

as:作用与强制类型转换是一样,但是永远不会抛出异常,即如果转换不成功,会返回null。


● 尽可能的使用as操作符,因为相对于强制类型转换来说,as更加安全,也更加高效。


● as在转换失败时会返回null,在转换对象是null时也会返回null,所以使用as进行转换时,只需检查返回的引用是否为null即可。


● as和is操作符都不会执行任何用户自定义的转换,它们仅当运行时类型符合目标类型时才能转换成功,也不会在转换时创建新的对象。


● as运算符对值类型是无效,此时可以使用is,配合强制类型转换进行转换。


● 仅当不能使用as进行转换时,才应该使用is操作符。否则is就是多余的。


原则4

 推荐使用条件属性而不是#if条件编译

            

● 由于#if/#endif很容易被滥用,使得编写的代码难于理解且更难于调试。C#为此提供了一条件特性(Conditional attribute)。使用条件特性可以将函数拆分出来,让其只有在定义了某些环境变量或设置了某个值之后才能编译并成为类的一部分。Conditional特性最常用的地方就是将一段代码变成调试语句。


● Conditional特性只可应用在整个方法上,另外,任何一个使用Conditional特性的方法都只能返回void类型。不能再方法内的代码块上应用Conditional特性。也不可以在有返回值的方法上应用Conditional特性。但应用了Conditional特性的方法可以接受任意数目的引用类型参数。


● 使用Conditional特性生成的IL要比使用#if/#Eendif时更有效率。同时,将其限制在函数层面上可以更加清晰地将条件性的代码分离出来,以便进一步保证代码的良好结构。


原则5

理解几个等同性判断之间的关系

● C#中可以创建两种类型:值类型和引用类型。如果两个引用类型的变量指向的是同一个对象,它们将被认为是“引用相等”。如果两个值类型的变量类型相同,而且包含同样的内容,它们被认为是“值相等”。这也是等同性判断需要如此多方法的原因。


● 当我们创建自己的类型时(无论是类还是struct),应为类型定义“等同性”的含义。C#提供了4种不同的函数来判断两个对象是否“相等”。

1)public static bool ReferenceEquals (object left, object right);判断两个不同变量的对象标识(object identity)是否相等。无论比较的是引用类型还是值类型,该方法判断的依据都是对象标识,而不是对象内容。

2)public static bool Equals (object left, object right); 用于判断两个变量的运行时类型是否相等。

3)public virtual bool Equals(object right); 用于重载

4)public static bool operator ==(MyClass left, MyClass right); 用于重载


● 不应该覆写Object.referenceEquals()静态方法和Object.Equals()静态方法,因为它们已经完美的完成了所需要完成的工作,提供了正确的判断,并且该判断与运行时的具体类型无关。对于值类型,我们应该总是覆写Object.Equals()实例方法和operatior==( ),以便为其提供效率更高的等同性判断。对于引用类型,仅当你认为相等的含义并非是对象标识相等时,才需要覆写Object.Equals( )实例方法。在覆写Equals( )时也要实现IEquatable<T>。


[网络安全提高篇] 一一一.ISC会议观后感之网络安全需要新战法和新框架

《构建之法》第四章读后感--软件工程

构建之法(前三章)读后感

程序员修炼之道读后感3

《构建之法》第四章“两人合作”读后感

构建之法读后感part4