当前位置:文档之家› 编写高质量代码改善C#程序的157个建议

编写高质量代码改善C#程序的157个建议

第二方面,避免分配额外的内存空间。对 CLR 来说,string 对象(字符串对象)是个很特 殊的对象,它一旦被赋值就不可改变。在运行时调用 System.String 类中的任何方法或进 行任何运算(如“=”赋值、“+”拼接等),都会在内存中创建一个新的字符串对象,这也意 味着要为该新对象分配新的内存空间。像下面的代码就会带来运行时的额外开销。
System.Convert 提供了将一个基元类型转换为其他基元类型的方法,如 ToChar、ToBo olean 方法等。值得注意的是,System.Convert 还支持将任何自定义类型转换为任何基 元类型,只要自定义类型继承了 IConvertible 接口就可以。如上文中的 IP 类,如果将 Ip 转换为 string,除了重写 Object 的 ToString 方法外,还可以实现 IConvertible 的 ToStr ing()方法
针对第一种情况:
public class FirstType {
public string Name { get; set; } }
public class SecondType {
public string Name { get; set; }
public static explicit operator SecondType(FirstType firstType)
1、确保尽量少的装箱
2、避免分配额外的内存空间
先来介绍第一个方面,请看下面的两行代码:
String str1="str1"+9; String str2="str2"+9.ToString();
从 IL 代码可以得知,第一行代码在运行时完成一次装箱的行为,而第二行代码中并没有发 生装箱的行为,它实际调用的是整型的 ToString()方法,效率要比装箱高。所以,在使用 其他值引用类型到字符串的转换并完成拼接时,应当避免使用操作符“+”来完成,而应该使 用值引用类型提供的 ToString()方法。
public static implicit operator Ip(string ip) {
Ip iptemp = new Ip(ip); return iptemp; }
//重写 ToString 方法 public override string ToString() {
return value.ToString(); } } class Program { public static void Main(string[] args)
string re2="123"+"abc"+"456"; 6"; }
///该代码等效于///string re2="123abc45
private static void NewMethod4() {
const string a="t"; string re="abc"+a; ///因为 a 是一个常量,所以该代码等效于 string=re=" abc"+"t"; 最终等效于 string re="abct"; }
所谓“基元类型”,是指编译器直接支持的数据类型。基元类型包括:sbyte、byte、short、 ushort、int、uint、long、ulong、char、float、double、bool、decimal、object、s tring。
int i = 0; float j = 0; j = i; ///int 到 float 存在一个隐式转换 i = (int)j; ///float 到 int 必须存在一个显式转换
由于使用 System.String 类会在某些场合带来明显的性能损耗,所以微软另外提供了一个 类型 StringBuilder 来弥补 String 的不足。
StringBuilder 并不会重新创建一个 string 对象,它的效率源于预先以非托管的方式分配 内存。如果 StringBuilder 没有先定义长度,则默认分配的长度为 16。当 StringBuilder 字符串长度小于等于 16 时,StringBuilder 不会重新分配内存;当 StringBuilder 字符长 度大于 16 小于 32 时,StringBuilder 又会重新分配内存,使之成为 16 的倍数。在上面 的代码中,如果预先判断字符串的长度将大于 16,则可以为其设定一个更加合适的长度(如 32)。StringBuilder 重新分配内存时是按照上次容量加倍进行分配的。当然,我们需要 注意,StringBuilder 指定的长度要合适,太小了,需要频繁分配内存,太大了,浪费空间。
就比如: 动作 Animal 类、Dog 类继承 Animal 类、Cat 类也继承自 Amimal 类。在进行 子类向基类转型的时候支持隐式转换,如 Dog 显然就是一个 Animal;而当 Animal 转型 为 Dog 的时候,必须是显式转换,因为 Animal 还可能是一个 Cat。
Animal animal = new Animal(); Dog dog = new Dog(); animal = dog; /////隐式转换,因为 Dog 就是 Animal ///dog=animal; ////编译不通过 dog = (dog)animal; /////必须存在一个显式转换
首先需要明确强制转换可能意味这两件不同的事情:
1、FirstType 和 SecondType 彼此依靠转换操作来完成两个类型之间的转换。 2、FirstType 是 SecondType 的基类。 类型之间如果存在强制转换,那么它们之间的关系要么是第一种,要么是第二种。不可能同 时是继承的关系,又提供了转型符。
微软还提供了另外一个方法来简化这种操作,即使用 string.Format 方法。string.Forma t 方法在内部使用 StringBuilder 进行字符串的格式化,代码如下所示:
public static void NewMethod4() {
string a = "t"; string b = "e"; string c = "s"; string d = "t"; string result = string.Format("{0}{1}{2}{3}", a, b, c, d); }
建议 3、区别对待强制转换与 as 和 is
首先来看一个简单的实例
FirstType firstType = new FirstType(); SecondType secondType = new SecondType(); secondType = (SecondType)firstType;
从上面的三行代码可以看出,类似上面的应该就是强制转换。
前言
本文主要来学习记录前三个建议。
建议 1、正确操作字符串
建议 2、使用默认转型方法
建议 3、区别对待强制转换与 as 和 is
其中有很多需要理解的东西,有些地方可能理解的不太到位,还望指正。
建议 1ห้องสมุดไป่ตู้正确操作字符串
字符串应该是所有编程语言中使用最频繁的一种基础数据类型。如果使用不慎,我们就 会为一次字符串的操作所带来的额外性能开销而付出代价。本条建议将从两个方面来探讨如 何规避这类性能开销:
用户自定义的类型也可以通过重载转换运算符的方式提供这一类转换:
public class Ip {
IPAddress value; public Ip(string ip) {
value = IPAddress.Parse(ip); }
//重载转换运算符,implicit 关键字用于声明隐式的用户定义类型转换 运算符。
string re=9+"456"; ////该方法发生了一次装箱,并调用一次 string.Cont act 方法
}
关于装箱拆箱的问题大家可以查看我之前的文章 而以下代码,字符串不会在运行时进行拼接,而是会在编译时直接生成一个字符串。
private static void NewMethod3() {
{
SecondType secondType = new SecondType() { Name = "转型
要完成这样的运行时字符串拼接(注意:是运行时),更佳的做法是使用 StringBuil der 类型,代码如下所示:
public static void NewMethod() {
////定义了四个变量 string a = "t"; string b = "e"; string c = "s"; string d = "t"; StringBuilder sb = new StringBuilder(a); sb.Append(b); sb.Append(c); sb.Append(d); ///提示是运行时,所以没有使用以下代码 //StringBuilder sb = new StringBuilder("t"); //sb.Append("e"); //sb.Append("s"); //sb.Append("t"); //string result = sb.ToString(); }
{ Ip ip = "192.168.1.1"; //通过 Ip 类的重载转换运算符,实现字符
串到 Ip 类型的隐式转换 Console.WriteLine(ip.ToString()); Console.ReadLine();
相关主题