如何编写更契合Unity的高效代码?
尽可能使用属性(property),而不是直接访问数据成员1. 属性允许将数据成员作为共有接口的一部分暴露出去,同时仍旧提供面向对象环境下所需的封装。属性这个语言元素可以让你像访问数据成员一样使用,但其底层依旧是使用方法实现的
2.可以非常轻松的在get和set代码段中加入检查机制
3.因为属性是用方法实现的,所以它拥有方法所拥有的一切语言特性
4.属性增加多线程的支持是非常方便的。你可以加强 get 和 set 访问器(accessors)的实现来提供数据访问的同步
5.属性可以被定义为virtual。
6.可以把属性扩展为abstract。
7.可以使用泛型版本的属性类型。
8.属性也可以定义为接口。
9.因为实现实现访问的方法get与set是独立的两个方法,在C# 2.0之后,你可以给它们定义不同的访问权限,来更好的控制类成员的可见性
10.而为了和多维数组保持一致,我们可以创建多维索引器,在不同的维度上使用相同或不同类型。
11.需要在类型的公有或保护接口中暴露数据
偏向于使用运行时常量(readonly),而不是编译时常量(const)
const
1.应仅仅在那些性能异常敏感,且常量的值在各个版本之间绝对不会变化时,再使用编译时常量。
2.编译时常量(const)的值会被目标代码中的值直接取代
3.仅能用于数值和字符串readonly
1.在运行时进行求值。引用运行时生成的IL将引用到readonly变量,而不是变量的值。
2.可以为任意类型。运行时常量必须在构造函数或初始化器中初始化,因为在构造函数执行后不能再被修改
3.可以用readonly值保存实例常量,为类的每个实例存放不同的值。而编译时常量就是静态的常量。
4.有时候你需要让某个值在编译时才确定,就最好是使用运行时常量
5.标记版本号的值就应该使用运行时常量,因为它的值会随着每个不同版本的发布而改变。
6.const优于readonly的地方仅仅是性能,使用已知的常量值要比访问readonly值略高一点,不过这其中的效率提升,可以说是微乎其微的。结论
综上,在编译器必须得到确定数值时,一定要使用const。例如特性(attribute)的参数和枚举的定义,还有那些在各个版本发布之间不会变化的值。除此之外的所有情况,都应尽量选择更加灵活的readonly常量。
推荐使用 is 或 as 操作符而不是强制类型转换
as和is操作符都不会执行任何用户自定义的转换,它们仅当运行时类型符合目标类型时才能转换成功,也不会在转换时创建新的对象
is
1.检查一个对象是否兼容于其他指定的类型,并返回一个Bool值,永远不会抛出异常
2.as运算符对值类型是无效,此时可以使用is,配合强制类型转换进行转换。
3.仅当不能使用as进行转换时,才应该使用is操作符。否则is就是多余的as
1.作用与强制类型转换是一样,但是永远不会抛出异常,即如果转换不成功,会返回null。
2.相对于强制类型转换来说,as更加安全,也更加高效
3.转换失败时会返回null,在转换对象是null时也会返回null,所以使用as进行转换时,只需检查返回的引用是否为null即可
使用条件属性(Conditional attribute)而不是 #if 条件编译
1.由于 #if/#endif 很容易被滥用,使得编写的代码难于理解且更难于调试
2.使用条件特性可以将函数拆分出来,让其只有在定义了某些环境变量或设置了某个值之后才能编译并成为类的一部分。Conditional特性最常用的地方就是将一段代码变成调试语句。
3.Conditional特性只可应用在整个方法上
4.任何一个使用Conditional特性的方法都只能返回void类型。
5.不能在方法内的代码块上应用Conditional特性。
6.不可以在有返回值的方法上应用Conditional特性
7.Conditional特性的方法可以接受任意数目的引用类型参数
8.Conditional特性生成的IL要比使用#if/#Eendif时更有效率
9.将其限制在函数层面上可以更加清晰地将条件性的代码分离出来,以便进一步保证代码的良好结构
了解 GetHashCode() 的一些坑
1.基于散列(hash)的集合定义键的散列值时,此类集合包括HashSet<T>和Dictionary<K,V>容器等
2.对引用类型来讲,索然可以正常工作,但是效率很低。对值类型来讲,基类中的实现有时甚至不正确。
3.在.NET中,每个对象都有一个散列码,其值由System.Object.GetHashCode()决定
4.实现自己的GetHashCode( )
5.如果两个对象相等(由operation==定义),那么他们必须生成相同的散列码。否则,这样的散列码将无法用来查找容器中的对象。
6.对于任何一个对象A,A.GetHashCode()必须保持不变。
7.对于所有的输入,散列函数应该在所有整数中按随机分别生成散列码。这样散列容器才能得到足够的效率提升
通过定义并实现接口替代继承
抽象基类(abstract class)
1.为一组相关的类型提供了一个共同的抽象
2.描述了对象是什么
3.可以为派生类提供一些具体的实现接口(interface)
1.一种契约式的设计方式
2.一个实现某个接口的类型,必须实现接口中约定的方法
3.描述了对象将如何表现其行为
4.不能包含实现
5.不能包含任何具体的数据成员
理解接口方法和虚方法的区别
1.接口中声明的成员方法默认情况下并非虚方法,所以,派生类不能覆写基类中实现的非虚接口成员。若要覆写的话,将接口方法声明为virtual即可
2.基类可以为接口中的方法提供默认的实现,随后,派生类也可以声明其实现了该接口,并从基类中继承该实现。
3.实现接口拥有的选择要比创建和覆写虚方法多。我们可以为类层次创建密封(sealed)的实现,虚实现或者抽象的契约。还可以创建密封的实现,并在实现接口的方法中提供虚方法进行调用
页:
[1]