介绍
在当今时代,编写代码并不困难。然而,编写干净且可伸缩的代码并不容易。在本文中,我们将讨论一些为我们的项目编写干净C#代码的技巧。乍一看,任何以前从未见过您的代码的开发人员都必须尽可能地理解它,它帮助我们更好地理解代码。
下面是编写干净C#代码的一些重要技巧。
使用好的IDE
首先,为您的技术堆栈选择最好的IDE。在我们的例子中,Visual Studio是C#最流行、最好的IDE之一。它是微软可靠的、完全的产品。一些开发人员也喜欢Rider IDE(付费)。使用这些IDE可以确保代码保持整洁。Visual Studio有相当稳定的智能感知特性,可以纠正和建议代码中的更改。
使用有意义的名字
命名变量可能是整个软件开发生命周期中最困难的部分。为变量和方法想一个有意义的名称是非常耗时的。但是跳过这个过程并随机命名也不是一个好主意,不是吗?
不建议写法
- int d;
这是命名变量最简单的方法,对吧?但是不要这样做。一个好的名称可以帮助其他开发人员理解变量/方法的上下文和用法。下面是您想要命名变量的方式。
建议写法
- int daysToAppocalypse;
使用骆驼/帕斯卡大小写符号
除了为变量选择一个合适的名称外,还要维护您编写名称的方式。理想情况下,我们使用骆驼大小写和Pascal大小写表示法作为最佳代码实践。不要在变量中使用随机大写字母。那看起来就是不漂亮!
驼峰式大小写符号
基本上,变量的第一个单词的第一个字母将是小写的,后面每一个单词的第一个字母应该是大写的。在命名局部变量和方法参数时,必须使用这种符号。
不建议写法
- int RandomInteger;
- string FirstName;
建议写法
- int randomInteger;
- string firstName;
帕斯卡案例符号
这里,您所有单词的首字母应该是大写,我们使用这种符号来命名方法和类。
不建议写法
- class program
- {
- static void main(string[] args)
- {
- Console.WriteLine("Hello World!");
- }
- }
建议写法
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Hello World!");
- }
- }
注意格式
对代码进行格式化可以提高代码的可读性。制表符优于空格,记得吗?
- class Program
- {static void Main(string[] args)
- {Console.WriteLine("Hello World!");
- }
- }
这个看起来怎么样?很讨厌,是吗?现在,Visual Studio有一个内置特性,可以完美地格式化代码。要做到这一点,只需到相关的类中按CTRL + K和CTRL + d,看到了吗?很酷,是吗?
在需要的时候添加注释
这是我们所有开发人员都讨厌的事情,不是吗?然而,从长远来看,添加几行评论/描述的方法确实能帮助你和其他开发人员。Visual Studio使它变得更加容易,只要在相关的方法上面输入///,VS就会自动为您生成一个包含方法参数的注释模板。
为什么这么酷?无论何时(从任何地方)调用这个方法,Visual Studio都会显示您的注释。相信我,这很有帮助。
P.S. 只有在情况需要的时候才添加评论。例如,当某个特定方法过于复杂,需要深入解释时。在这种情况下,您需要添加注释。记住,维护注释也将成为一项任务,因此要有节制地使用注释。
重用代码
编写可重用的代码是非常重要的。它可以减少项目中的总代码行数,并提高效率。您不希望通过多个类复制粘贴一个函数。相反,您可以做的是创建一个共享库项目,并在每个必需的项目中引用它。通过这种方式,我们构建了可重用的函数。而且,如果需要进行任何修改,您只需要更改共享库中的代码,而不是在任何地方更改。
保持类尽可能小
根据Solid原则,您必须将类隔离为只有一个职责函数的小块。这有助于我们实现松散耦合的代码。确保您在查看类时不需要反复滚动。这可以是一个一般的经验法则。
使用设计模式
这可能是架构师级别的开发人员需要做的事情。确定将哪种设计模式应用于哪种场景需要大量的经验。设计模式基本上是能够在架构解决方案时提供可重用解决方案的模式。
把您的解决方案组织好
你构建结构化的解决方案吗?建立一个这样的系统是非常令人满意和重要的。下面是我遵循洋葱架构的一个解决方案。
在单个项目中仍然可以完成所有工作。但是,为了支持可伸缩性和松散耦合的解决方案,我们将它们分成不同的层,如应用程序、领域、基础设施等。
这里还有一些其他的优势:
- 可重用性——如果您想将同一个项目用于另一个解决方案,您可以这样做。
- 改进的安全性
- 高度可维护的
- 可伸缩的
- 控制反转等
避免魔法字符串/数字
什么是魔法字符串?它们是直接在应用程序代码中指定的字符串,对应用程序的行为有直接影响。换句话说,不要在应用程序中使用硬编码的字符串或值。当应用程序增长时,跟踪这些字符串是很困难的。此外,这些字符串可以与某种外部引用相关联,如文件名、文件路径、URL等。在这种情况下,当资源的位置发生变化时,必须更新所有这些神奇的字符串,否则应用程序将中断。考虑下面的例子:
- if(userRole == "Admin")
- {
- //logic here
- }
你可以这样写:
- const string ADMIN_ROLE = "Admin"
- if(userRole == ADMIN_ROLE )
- {
- //logic here
- }
或者,您也可以为用户角色创建枚举并简单地使用它。这是一种更简洁的编写代码的方式。
删除未使用的代码
通常会有注释掉未使用代码的做法,这最终会增加应用程序编译时的代码行数。你不应该这样做。您可以使用像Git这样的源控件来确保您可以在任何时候恢复。宁愿使用Git而不是注释掉代码。
使用方法链接
这是Microsoft在默认生成代码中广泛使用的一种常见技术。在这里,每个方法返回一个对象,这些函数将被链接在一起。认识吗?这是方法链接的一个很好的例子。
- services.AddHealthChecks().AddSqlServer(_configuration.GetConnectionString("DefaultConnection"));
下面是一个详细的例子。我们有一个student类和另一个创建并返回数据填充student对象的随机方法。
- public class Student
- {
- public string Name { get; set; }
- public int Age { get; set; }
- }
- public Student SomeMethod()
- {
- Student testStudent = new Student();
- testStudent.Name = "Jay Krishna Reddy";
- testStudent.Age = 25;
- return testStudent;
- }
对我们开发人员来说,设置Student对象的值可能不是问题。但是,让我们假设一个单元测试开发人员必须在您的类上进行测试,并且实际上没有C#,或者您想通过简化整个过程来取悦您的客户。这就是连贯接口的用武之地。创建一个新的连贯类,如下所示:
- public class StudentFluent
- {
- private Student student = new Student();
- public StudentFluent AddName(string name)
- {
- student.Name = name;
- return this;
- }
- public StudentFluent AddAge(int age)
- {
- student.Age = age;
- return this;
- }
- }
- public StudentFluent SomeMethod()
- {
- return new StudentFluent().AddName("Jay Krishna Reddy").AddAge(25);
- }
这很有意义,并且在一个全新的层次上提高了可读性,对吗?方法链接的另一个简单例子如下:
- public string AnotherMethod()
- {
- string name = "Jay Krishna";
- return name.Replace("J", "A").Replace("A", "J").Replace(".", string.Empty);
- }
使用异步/等待
异步编程是最好的选择!异步编程在处理需要一些时间才能完成计算的函数时,有助于提高总体效率。在这样的函数执行期间,对于最终用户来说,整个应用程序似乎是冻结的。这导致了糟糕的用户体验。在这种情况下,我们使用异步方法来释放主线程。
不要在catch块使用Throw ex
您确实不希望只是在捕获异常并丢失堆栈跟踪数据后对其进行“throw ex”。 只需使用“throw”即可。 通过使用此方法,您还可以存储堆栈跟踪,这对于诊断很重要。
不建议写法
- try
- {
- // Do something..
- }
- catch (Exception ex)
- {
- throw ex;
- }
建议写法
- try
- {
- // Do something..
- }
- catch (Exception ex)
- {
- throw;
- }
使用三元运算符
考虑下面的例子,我相信你们很多人仍然在遵循这一做法。
- public string SomeMethod(int value)
- {
- if(value == 10)
- {
- return "Value is 10";
- }
- else
- {
- return "Value is not 10";
- }
- }
但如果有更好更清洁的方法呢?引入三元操作符。
现在我们之前写的多行代码可以使用三元运算符缩减为一行,您可以开始想象这将节省多少行代码!
- public string SomeMethod(int value)
- {
- return value == 10 ? "Value is 10" : "Value is not 10";
- }
使用Null合并操作符
类似地,我们还有另一个操作符,可以在进行null检查时派上用场。??这个操作符在C#中称为Null合并操作符。
考虑另一个例子,下面是一个接受Student对象作为参数并检查空对象的小函数。如果为空,返回一个带有数据的新对象,否则返回相同的对象。
- public Student SomeMethod(Student student)
- {
- if (student != null)
- {
- return student;
- }
- else
- {
- return new Student() { Name = "Jay Krishna Reddy" };
- }
- }
让我们添加操作符并缩小这个函数!
- public Student SomeMethod(Student student)
- {
- return student ?? new Student() { Name = "Jay Krishna Reddy" };
- }
首选字符串插值
每次您要向字符串添加动态值时,我们都倾向于使用复合格式或仅使用加号将其添加。
- public string SomeMethod(Student student)
- {
- return "Student Name is " + student.Name + ". Age is " + student.Age;
- }
从C# 6开始,引入了String Interpolation功能。 这提供了一种更具可读性和凉爽性的语法来创建格式化的字符串。 这是使用内插字符串的方法。
- public string SomeMethod(Student student)
- {
- return $"Student Name is {student.Name}. Age is {student.Age}";
- }
使用表达体法
这样的方法用于方法体甚至比方法定义本身小得多的场景中。为什么要浪费括号和代码行呢?下面是编写表达式体方法的方法。
- public string Message() => "Hello World!";
避免太多参数
太多的参数总是一场噩梦。如果你倾向于有超过3个参数输入到任何方法,为什么不把它包装到一个请求对象或其他东西,然后传递?让我们看一个小例子。
- public Student SomeMethod(string name, string city, int age, string section, DateTime dateOfBirth)
- {
- return new Student()
- {
- Age = age,
- Name = name,
- //Other parameters too
- };
- }
你可能希望它是这样的。
- public Student SomeMethod(Student student)
- {
- return student;
- }
不要忽略捕捉到的错误
这是我一直在做的事情。你们很多人很有可能也会这样做。我们添加了一个try-catch块并忽略了错误处理,对吗?处理此类错误并将其记录到表或磁盘是一种很好的实践。
- public void SomeMethod()
- {
- try
- {
- DoSomething();
- }
- catch
- {
- }
- }
- public void SomeMethod()
- {
- try
- {
- DoSomething();
- }
- catch (Exception ex)
- {
- LogItSomewhere(ex);
- }
- }