编写更好的 C# 代码的技巧
介绍
在阅读本指南之前,请查看本系列的第一本指南:编写更好的 C# 代码简介。
阅读本指南之前您应该了解以下几件事:
- C# 第 6 版中的改进
- .NET 框架中的 LINQ
- C# 中的异步编程和Task对象
- C# 中的不安全编程,允许你进入内存管理
不注重绩效
需要注意的是,我不会谈论改变程序性能、提高效率或减少程序运行所需的时间。通过编写良好的 C# 代码,您可以在几秒钟内提高程序性能,但以下提示并不能保证您的代码性能会更好。
空值检查
当一个未初始化的对象回来报复时,您是否会因为NullReferenceException而烦恼?在程序中进行空值检查有很多好处,不仅可以提高可读性,还可以确保程序不会因内存问题(例如内存中不存在变量)而终止。这些可能会影响程序的安全性以及团队拥有的良好 UI 和 UX 指南。大多数情况下,空值异常是由于以下原因引发的:
string name = null;
Console.WriteLine(name);
在大多数情况下,除非您修复此问题,否则编译器本身不会继续运行,但如果您设法欺骗编译器,使其认为变量有值,但在运行时却没有值,则会出现空引用异常。为了克服这个问题,您可以执行以下操作:
string name = null;
// Try to enter the value, from somewhere
if(name != null) {
Console.WriteLine(name);
}
此安全检查将确保在调用此变量时该值可用。否则,它将朝其他方向移动并远离错误路径。然而,在 C# 6 中,还有另一种方法可以克服此错误。考虑这样一种情况:您的数据库已设置,数据表已设置,您的人员已找到,但找不到他们的就业详细信息。您能找到他们工作的公司吗?
var company = DbHelper.PeopleTable.Find(x => x.id == id).FirstOrDefault().EmploymentHistory.CompanyName; // Error
如果您这样做,将会出现错误,因为我们只能在这些值的列表中向上移动几步。然后我们最终遇到了一个空值,一切都丢失了。C# 6 提出了一种克服这些情况的新方法,即在可以为空的值和字段后使用安全导航运算符;?。像这样:
var company = DbHelper?.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName; // Works
如果前一个值不为空,此代码将仅检查下一个值。如果前一个值为空,它将返回空并将空保存为 company 的值,而不是抛出错误。当您将检查留给框架本身时,这会很方便,但是,尽管如此,您仍然必须在最后检查其余值是否为空。
var company = DbHelper.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName;
if(company != null) {
// Final process
}
但你明白了,你不必编写代码并检查所有内容是否为空,而是可以进行简单的检查并执行程序中想要的操作和逻辑。否则,就需要一个try...catch包装器或多个if...else块来控制程序在系统中的导航方式。
异步编程模式
如果您使用 C# 5 进行编程,那么您已经在使用 async/await 关键字来提高应用程序的响应能力。如果不是这种情况,那么我建议在应用程序的源代码中使用异步编程模式。这不仅可以提高程序的响应能力,还可以提高应用程序的可读性。在源代码中使用异步模式的一些好处是:
- 代码路径开始变得更加合理。如果有一个进程在后台运行,程序员可以了解程序应该在哪里。
- 应用程序挂起问题将消失。大多数与应用程序冻结相关的问题直接来自代码。当 UI 线程无法更新 UI 时,用户会认为应用程序挂起且没有响应,但事实并非如此。异步方法在这方面确实有很大帮助。
- 基于 Windows 运行时的应用程序完全基于此方法。您将(并且必须!)在某个 Windows 运行时应用程序中使用此方法来解决应用程序挂起或不良编程习惯等问题。
自从有了线程,代码执行的并行化就出现了。异步已经成为程序和应用程序的重要组成部分,所以你也应该考虑使用它。
C# 字符串构建
如今,字符串已成为应用程序的重要组成部分,构建字符串可能耗费大量时间,同时还会导致应用程序性能下降。在 C# 程序中,构建字符串的方法有很多种。以下是其中几种方法:
string str = ""; // Setting it to null would cause additional problems.
// Way 1
str = "Name: " + name + ", Age: " + age;
// Way 2
str = string.Format("Name: {0}, Age: {1}", name, age);
// Way 3
var builder = new StringBuilder();
builder.Append("Name: ");
builder.Append(name);
builder.Append(", Age: ");
builder.Append(age);
str = builder.ToString();
请注意,C# 中的字符串是不可变的。这意味着如果您尝试更新它们的值,它们将被重新创建,并且先前的句柄将从内存中删除。这就是为什么方法 1 看起来是最好的方法,但经过进一步思考,事实并非如此。最好的方法是方法 3,它允许您构建字符串而不必在内存中重新创建对象。但是,C# 6 引入了一种全新的在 C# 中构建字符串的方法,这种方法比您以前想象的要好得多。新的字符串插值运算符$为您提供了以最佳方式执行字符串构建的功能。字符串插值如下:
static void Main(string[] args)
{
// Just arbitrary variables
string name = "";
int age = 0;
// Our interest
string str = $"Name: {name}, Age: {age}";
}
只需一行代码,编译器就会自动将其转换为 string.Format ()版本。为了证明这一点,我们将详细说明此 C# 程序生成的字节码,并向您展示这将如何自动更改语法以读取字符串的格式。
IL_0000: nop
IL_0001: ldstr ""
IL_0006: stloc.0 // name
IL_0007: ldc.i4.0
IL_0008: stloc.1 // age
IL_0009: ldstr "Name: {0}, Age: {1}"
IL_000E: ldloc.0 // name
IL_000F: ldloc.1 // age
IL_0010: box System.Int32
IL_0015: call System.String.Format
IL_001A: stloc.2 // str
IL_001B: ret
可以看出,这显示了语法如何改回我们已经看到的语法。有关详细信息,请参阅 IL_0009 。当其他人阅读程序时,这会让您的程序看起来更简洁,并且如果要构建的字符串较小,还可以提高性能。如果字符串较大,请使用StringBuilder。
下一步
继续阅读本系列的下一篇指南,了解有关编写更好的 C# 代码的更多技巧。
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~