改善C# 程序 的N个建议(1-5)
最近有空了,还有本来想趁最近空闲时间深入学习一下java的,但是…(我还没能力去黑java,只能说我用不习惯,有点像用惯Windows 操作系统的人转用其他系统一样,会有些不习惯).而且很长一段时间没写C# 了,加上看到一本《编写高质量代码:改善C#程序的157个建议》还不错,我正好可以回顾一下C#,我是靠C# 入门程序员的.看家本领不能丢啊,所以有了写此系列文章的想法.一下就说多了,切入正题:
建议1:对String 与值类型进行字符串拼接使用.ToString()在拼接.(string str=”str”+9.ToString())
string str1 = "str" + 9; string str2 = "str" + 9.ToString();//better
例如上面这两段代码,第一行,需要装箱.第二行则不用装箱.证据如下:
L_0000: nop L_0001: ldstr "str" L_0006: ldc.i4.s 9 L_0008: box int32 L_000d: call string [mscorlib]System.String::Concat(object, object) L_0012: stloc.0 L_0013: ldstr "str" L_0018: ldc.i4.s 9 L_001a: stloc.3 L_001b: ldloca.s num L_001d: call instance string [mscorlib]System.Int32::ToString() L_0022: call string [mscorlib]System.String::Concat(string, string) L_0027: stloc.1
可以看到第四行,”box”指令.说明发生装箱操作.虽然只有一次装箱操作.对系统整体性能毫无影响.而L_001d 调用了System.Int32.ToString()通过IL中看是调用非托管代码,无法继续跟踪.但是我有代码洁癖,能”干净”点就干净点.
建议2:要清楚如何对自定义类型做类型转换(IP ip = (IP)"192.168.0.1") .
自定义一个IP类:
public class IP:IConvertible,IFormatProvider { IPAddress value; public IP(string ip) { IPAddress.TryParse(ip, out value); } public static implicit operator IP(string ip) { IP iptemp=new IP(ip); return iptemp; } public override string ToString() { return value.ToString(); } //省略部分代码... public bool ToBoolean(IFormatProvider provider) { throw new InvalidCastException("IP-to-Boolean conversion is not supported."); } public string ToString(IFormatProvider provider) { return value.ToString(); } //省略部分代码... public object GetFormat(Type formatType) { return null; } }
就可以这样调用:
IP ip = new IP ("192.168.0.1"); ip = (IP)("192.168.0.2"); bool boolIP = ip.ToBoolean(ip); bool boolIP2 = Convert.ToBoolean(ip);
隐式转换需要实现隐式操作符(implicit operator)的方法.如果要转换成基元类型就要实现IConvertible.
建议3: 强制转型和as ,is 的用法
强制转型一般有两种情况:
1.两种类型依靠转换操作符完成彼此间的转型(如:隐式转换和Convert).
2.子类和父类之间的转型.
第一种情况,建议2 已经详细阐述过了.那个第二种情况应该怎么处理呢?
as ,is 就是C#语言设计师(Anders.Hejlsberg)针对第二种情况进行设计的关键字.
is:判断是否是继承关系(返回bool)
as: 提供父类向子类的转型.如果转型失败,也不会抛出 Exception ,只会返回null.
public static void FatherConvertToSun(Father father) { if(father is sun) { Sun sun = father as Sun; //省略部分代码.... } }
建议4:基元类型之间的强制转型(值类型转为引用类型).
值类型都提供了Tryparse 和Parse 方法提供转型.测试代码如下:
public static void TestTryParse(string item) { double number = 0; Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; i < 1000; i++) { if (double.TryParse(item, out number) == true) { number = 0; } } long time = sw.ElapsedTicks; if (double.TryParse(item, out number) == true) { Console.WriteLine(string.Format("TryParse成功耗时:{0}", time)); } else { Console.WriteLine(string.Format("TryParse失败耗时:{0}", time)); } }
public static void TestParse(string item) { Stopwatch sw = Stopwatch.StartNew(); double number = 0; for (int i = 0; i < 1000; i++) { try { number = double.Parse(item); } catch (Exception ex) { number = 0; } } long time = sw.ElapsedTicks; if (number != 0) { Console.WriteLine(string.Format("Parse成功耗时:{0}", time)); } else { Console.WriteLine(string.Format("Parse失败耗时:{0}", time)); } }
结果如下:
TyeParse的效率比Parse 的效率高得多,特别是转型失败的时候.建议:值类型与引用类型之间使用TryParse转型.
建议5:可空值类型的使用环境.
1.从数据库中读取数字可空型字段(decimal,int)时,使用可空类型可以防止把null赋值给值类型报异常.
2.从分布式系统中,服务器需要接收和解析客户端发来的数字型数据.这些数字型数据也很有可能为空.
Nullable<int> i=null;//声明赋值方式1; int ? n=null;//声明赋值方式2; int j=n?? 0;//如果n为空将0赋值给j,否则 j=i;
可空类型有一个属性(HasValue)可以判断可空类型是否为null.
今天就到这来,明天继续5条建议.