我们先来讲一个小故事:为什么追女孩子总是从加微信开始?为什么不是要电话,不是写情书呢?你当然可以要电话,但你要电话时,旁人会以为你是销售。你也可以写情书,但每个字都要自己写,麻烦,还不知道女孩到底看还是没看你的情书。所以现代社会追一个女孩子都达成了一个共识:从要微信开始。因为微信交流方便,可以看朋友圈、点赞,互动性很好,慢慢的你们就有可能有交集了。当然,你可能有其他方式搭讪,但要微信绝对是多数人的首选,这就是搭讪的最佳实践。
最佳实践通常是指在某个特定领域或行业中,经过广泛验证并被认为是最有效、最可靠的方法或策略。那在编程领域的最佳实践呢,就是程序员总结出来的最简洁、最有效的开发方式。
那既然是最佳实践,肯定会带有笔者的个人情感,我认为的好方法,其他人从另外一个维度来看,却糟糕透了,因此最佳实践并不是唯一的。我总结的C#开发者的最佳实践,是我多年的编程经验总结的一套编程方法论,其中很多经验是踩了很多坑才悟出来的,现在我开发始终坚持这些原则,也希望这些方法对您编程有帮助。

C#编程的最佳实践
最佳实践1:命名要合理
在新项目中,默认项目名称和解决方案名称通常是“consoleApplication ”,这是糟糕的命名方式,因为无法理解它们的实际功能,当你有多个项目时,很可能不知道某个项目的具体功能。应该为项目命名一个具有实际意义的名称。例如,将项目命名为“consoleMathMethod”,这个名称告诉我们它是应用程序的控制台部分,并且与数学方法有关。
另外一个就是变量名,比如温度,你可以用汉语拼音“wendu”,也可以用汉语拼音首字母“WD",这些都可以。但是,这很容易出岔子,比如一个哥们想给”社保“起个名字,就叫”shebao“,但这哥们图省事,简写成”sb",这哥们不会被社保局的人追着打吧,毕竟“shebao”和“sb”之间还是有区别的!
还是用回英文吧:Temperature,也可以用Temper。
在这个示例中,如果要添加多个类,应为每个类创建一个单独的文件。例如,创建一个名为“Person”的类文件和一个名为“Guest”的类文件,我们把它放到两个cs文件中。这样可以通过查看文件结构,轻松找到每个类的位置。
当然了,你非要犟,就是要把这两个类写在一个文件中,就像下面这个例子:文件的名字是MyClass.cs,但点击进去时,却发现有两个其他的类,Person类和Guest类,这个习惯很不好,甚至可以说恶劣,别人接收你的代码肯定爆粗口,有时候你自己找不到相关类的文件时,也会忍不住给自己一个大嘴巴子。
//MyClass.cspublic class Person { public string Name { get; set; } // ... 其他成员 ... }public class Guest { public Person Host { get; set; } public DateTime ArrivalDate { get; set; } // ... 其他成员 ... }
最佳实践3:使用属性而不是公共变量
属性允许在获取和设置值时执行额外的逻辑,例如验证数据的合法性或引发事件。这确保了数据的一致性和完整性。例如,使用属性可以确保在设置负值之前进行验证。
private int age;public int Age{ get { return age; } set { if (value >= 0) { age = value; } else { throw new ArgumentOutOfRangeException("Age cannot be negative."); } }}
相比之下,公共字段无法实现这种控制:
public int age;
最佳实践4:方法应只做一件事
方法应只做一件事,且只做一件事。将复杂的方法拆分为多个简单的方法,使每个方法职责单一。这不仅有助于提高代码的可读性,也更容易进行调试和维护。遵循单一职责原则,有助于确保代码模块的独立性和复用性。下面的例子,每个方法只关注其自身的功能,简化了代码的逻辑。
public void ProcessOrder(){ ValidateOrder(); CalculateTotal(); SaveOrder();}private void ValidateOrder() { / 验证订单逻辑 / }private void CalculateTotal() { / 计算总价逻辑 / }private void SaveOrder() { / 保存订单逻辑 / }
最佳实践5:仅在必要时使用公共修饰符
默认情况下,应将方法和属性设为私有(private),只有在需要从类外部访问时,才将其设为公共(public)。这样可以减少不必要的访问权限,增强类的封装性和安全性。例如,我们将age 设为私有字段,类外的成员就无法直接访问了,如果类外的成员想访问,可以通过公共方法GetAge()来访问。
public class Person{ public string FirstName { get; set; } // 公共属性 public string LastName { get; set; } // 公共属性 private int age; // 私有字段 public int GetAge() // 公共方法,用于访问私有字段 { return age; }}
这种做法有助于确保只有需要公开的方法和属性才会被暴露,其他实现细节保持私有。
最佳实践6:保持代码简单代码应尽量保持简单,不要编写过于复杂的代码。如果发现代码非常复杂,应暂停并考虑是否有更简单的方法实现同样的功能。简化代码不仅有助于提高可读性,也更容易进行调试。例如,使用foreach循环而不是复杂的for循环:
// 简单的foreach循环foreach (var person in people){Console.WriteLine($"Hello, {person.FirstName} {person.LastName}");}// 复杂的for循环,这里就是举例子,实际中应该也没人这么写for (int i = 0; i < people.Count; i++){Console.WriteLine($"Hello, {people[i].FirstName} {people[i].LastName}");}
什么是保持一致性,大家都军训过,稍息出的是左脚,敬礼是抬右手,但有个二货,他就是反着来,稍息出右脚,敬礼抬左手。我已经能想象教官喷他狗血淋头的样子了。编程也是这样,做一件事时,保持一样的风格
变量声明:始终使用相同的方式声明变量。例如,在C#中,可以选择使用明确的类型声明或使用var关键字,但无论选择哪种方式,都应在整个项目中保持一致。
// 不一致的变量声明int age = 25;var name = "Alice";// 一致的变量声明int age = 25;string name = "Alice";命名约定:为类、方法、变量等制定并遵循一致的命名约定。例如,类名使用Pascal命名法,方法名使用Camel命名法。// Pascal命名法用于类名public class UserManager {}// Camel命名法用于方法名public void getUserDetails() {}代码格式:保持一致的代码格式,包括缩进、空格和换行。使用自动格式化工具可以帮助维持一致的代码格式。// 不一致的代码格式public void DoSomething(){if(true){Console.WriteLine("Hello");}}// 一致的代码格式public void DoSomething(){ if (true) { Console.WriteLine("Hello"); }}注释风格:保持一致的注释风格和格式。确保注释清晰且简洁,并与代码保持同步。// 单行注释// 计算总和int sum = a + b;// 多行注释/计算总和变量a和b是输入参数/int sum = a + b;
在if语句中始终使用大括号,即使条件语句只有一行代码。这样做有以下几个好处:(1)防止错误:在只有一行代码的if语句中,如果未来需要增加新代码,容易因为忘记添加大括号而导致错误。始终使用大括号可以避免这种情况。(2)提高可读性:大括号使代码结构更加清晰,容易辨认条件语句的范围,提高代码的可读性。(3)一致性:无论条件语句的代码行数,始终使用大括号可以保持代码风格的一致性。以下是一个示例:
使用字符串插值在连接字符串时,使用字符串插值($"")而不是使用加号(+)连接。这不仅更易读,还能提高代码的效率。
为什么使用字符串插值?(1)可读性:字符串插值使得代码更清晰、更易读。变量和文本混合在一起,直观易懂。(2)效率:字符串插值在编译时进行优化,通常比使用加号连接字符串更高效。(3)简洁性:使用字符串插值可以减少代码量,使代码更加简洁。我们来看下面这个例子:
//使用加号连接字符串string name = "Alice";int age = 30;string message = "Name: " + name + ", Age: " + age;Console.WriteLine(message);//使用字符串插值string name = "Alice";int age = 30;string message = $"Name: {name}, Age: {age}";Console.WriteLine(message)
避免使用全局变量,而应通过参数传递或其他方式共享数据。这样可以减少内存占用,并提高代码的模块化和可维护性。
为什么避免使用全局变量?(1)减少耦合:全局变量会导致代码之间的高耦合,难以维护和扩展。(2)提高模块化:通过参数传递等方式共享数据,可以使代码更模块化,便于测试和复用。(3)降低错误风险:全局变量的值可以在程序的任何地方被修改,容易引起难以发现的错误。(4)优化内存使用:全局变量会一直占用内存,直到程序结束,局部变量和参数传递可以有效管理内存使用。
我们来看一个例子:
//使用全局变量(不推荐)public class Program{ public static int globalCounter = 0; public static void Main() { IncrementCounter(); Console.WriteLine(globalCounter); } public static void IncrementCounter() { globalCounter++; }}//使用参数传递(推荐)public class Program{ public static void Main() { int counter = 0; counter = IncrementCounter(counter); Console.WriteLine(counter); } public static int IncrementCounter(int counter) { return ++counter; }}
最佳实践11:注释和文档
为什么注释和文档很重要?(1)提高可维护性:好的注释和文档能帮助其他开发人员快速理解代码,尤其是在原始开发人员不在时。(2)减少沟通成本:详细的文档和注释可以减少开发团队间的沟通成本,提升工作效率。(3)明确代码意图:通过注释解释为什么做某事,可以让代码意图更加明确,避免误解。(4)便于长期维护:随着时间推移,详细的注释和文档可以帮助维护人员更好地理解和修改代码。
注释的最佳实践,我列出了一下几点:
(1)解释“为什么”而不是“如何”:注释应解释代码的目的和原因,而不是描述代码的工作原理。
// 坏的注释// Increment the counter by 1counter++;// 好的注释// 增加计数器,因为我们需要跟踪操作次数counter++;
(2)简洁和相关:保持注释简洁并且与代码相关,避免冗长和不必要的注释。
// 坏的注释//这个函数的功能是求解两数之和,并且将和作为返回值public int Add(int a, int b){return a + b;}// 好的注释// 这个函数用于处理交易时的金额合并public int Add(int a, int b){return a + b;}
文档的最佳实践
(1)设置说明:文档应包括如何设置项目的详细说明,确保新开发人员能快速上手。
## 设置说明1. 克隆仓库:`git clone https://github.com/example/project.git`2. 安装依赖:`npm install`3. 运行项目:`npm start`
(2)使用详细信息:包括项目的使用说明和示例,帮助用户了解如何使用项目。
## 使用说明要运行应用程序,请执行以下命令:```bashnpm start第二步:……第三步……
最佳实践12:不要信任用户输入
永远不要相信互联网,因为你不知道对方是魔鬼还是凤姐。用户输入的数据可能会导致应用程序崩溃,甚至引发安全漏洞,一定要对用户输入进行严格的验证和处理。
为什么不信任用户输入?(1)安全性:未验证的用户输入可能导致SQL注入、XSS攻击等安全漏洞。(2)稳定性:未验证的用户输入可能导致应用程序崩溃或产生意外行为。(3)数据完整性:未验证的用户输入可能导致数据库中的数据不一致或错误。
最佳实践13:在编写代码之前进行计划为什么在编写代码之前进行计划?
(1)提高效率:提前计划可以减少返工和修复错误的时间,从而提高开发效率。(2)减少错误:详细的计划和设计有助于识别潜在的问题,并在编码之前解决这些问题。(3)明确目标:有了明确的计划,开发人员可以更清楚地知道他们需要实现什么,以及如何实现。(4)团队协作:计划和设计文档可以作为团队成员之间的沟通工具,确保所有人对项目目标和实现方法有一致的理解。
如何进行有效的计划和设计?
我们以一个用户登录系统为例,来做详细说明:
(1)需求分析:在编写代码之前,首先需要进行需求分析,明确项目的目标和要求。
# 用户登录系统需求分析
- 用户可以使用电子邮件和密码登录。
- 系统需要验证用户的电子邮件和密码。
- 用户成功登录后,系统应显示欢迎页面。
(2)系统设计:根据需求分析,设计系统的整体架构和组件,包括数据库设计、模块划分和接口设计。
# 用户登录系统设计
## 数据库设计
- 用户表(Users)
- 用户ID(UserID,主键)
- 电子邮件(Email)
- 密码(Password)
## 模块划分
- 用户接口模块(User Interface Module)
- 用户验证模块(User Authentication Module)
- 数据库访问模块(Database Access Module)
## 接口设计
- 登录接口(Login API)
- 输入:电子邮件、密码
- 输出:登录成功或失败信息
(3)流程图和用例图
使用流程图和用例图等工具,直观地展示系统的工作流程和用户交互。登录流程图如下图所示:
(4)编写伪代码或原型
在开始实际编码之前,编写伪代码或开发原型,以验证设计的可行性和合理性。伪代码如下:
Function Login(email, password) If ValidateEmail(email) And ValidatePassword(password) Then If AuthenticateUser(email, password) Then Display "Welcome" Else Display "Invalid email or password" End If Else Display "Invalid input format" End IfEnd Function
你们肯定遇到过这样的人,床垫不整齐一点,如果不拉平整,那一晚上他都睡不着觉,和这些强迫症患者相处,很累。程序员中也有类似的人,比如前人留下的代码质量很烂,但能稳定运行,他就是要重构,重新设计框架,他自己那一部分改动就算了,很有可能会牵扯到你负责那个模块,你也得跟着折腾。
很多人做项目时,代码都写了好多,又觉得之前的设计框架不太合理,又想重新弄,想设计一个更完美的框架。其实,哪有什么完美的框架,一个项目做完,肯定有各种瑕疵,我觉得能按时交付就可以了,至于本项目某些地方设计不足,我们在下一个项目在完善就可以了。我们来举个例子:
我们要设计两个篮子:一个篮子装水果,一个篮子装蔬菜。于是我们就购买各种材料,编制了两个篮子。但是,使用者并没有完全按照这个设计去用者两个篮子,装蔬菜的篮子里装了水果,装水果的篮子也装了蔬菜,这或许就是不完美就是完美吧。
推进一个项目时也应该有这种心态:小步前进,快速迭代。遇到非致命问题时,可以先摆一摆,计划也跟着实际进度不断调整。