clean-code-dotnet

clean-code-dotnet

实用的.NET代码优化和最佳实践指南

clean-code-dotnet是一个面向.NET开发者的代码优化指南项目。它涵盖命名规范、变量使用、函数编写等多个方面,提供了一系列编写可读性强、易于维护和重构的代码的最佳实践。该项目不仅列举具体技巧,还阐述背后原理,是帮助开发者提升.NET代码质量的实用资源。

Clean Code.NET命名函数变量Github开源项目

Clean Code concepts adapted for .NET/.NET Core

If you liked clean-code-dotnet project or if it helped you, please give a star :star: for this repository. That will not only help strengthen our .NET community but also improve skills about the clean code for .NET developers in around the world. Thank you very much :+1:

Check out my blog or say hi on Twitter!

Table of Contents

Introduction

Humorous image of software quality estimation as a count of how many expletives you shout when reading code

Software engineering principles, from Robert C. Martin's book Clean Code, adapted for .NET/.NET Core. This is not a style guide. It's a guide to producing readable, reusable, and refactorable software in .NET/.NET Core.

Not every principle herein has to be strictly followed, and even fewer will be universally agreed upon. These are guidelines and nothing more, but they are ones codified over many years of collective experience by the authors of Clean Code.

Inspired from clean-code-javascript and clean-code-php lists.

Clean Code .NET

Naming

<details> <summary><b>Avoid using bad names</b></summary> A good name allows the code to be used by many developers. The name should reflect what it does and give context.

Bad:

int d;

Good:

int daySinceModification;

⬆ Back to top

</details> <details> <summary><b>Avoid Misleading Names</b></summary>

Name the variable to reflect what it is used for.

Bad:

var dataFromDb = db.GetFromService().ToList();

Good:

var listOfEmployee = _employeeService.GetEmployees().ToList();

⬆ Back to top

</details> <details> <summary><b>Avoid Hungarian notation</b></summary>

Hungarian Notation restates the type which is already present in the declaration. This is pointless since modern IDEs will identify the type.

Bad:

int iCounter; string strFullName; DateTime dModifiedDate;

Good:

int counter; string fullName; DateTime modifiedDate;

Hungarian Notation should also not be used in paramaters.

Bad:

public bool IsShopOpen(string pDay, int pAmount) { // some logic }

Good:

public bool IsShopOpen(string day, int amount) { // some logic }

⬆ Back to top

</details> <details> <summary><b>Use consistent capitalization</b></summary>

Capitalization tells you a lot about your variables, functions, etc. These rules are subjective, so your team can choose whatever they want. The point is, no matter what you all choose, just be consistent.

Bad:

const int DAYS_IN_WEEK = 7; const int daysInMonth = 30; var songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' }; var Artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' }; bool EraseDatabase() {} bool Restore_database() {} class animal {} class Alpaca {}

Good:

const int DaysInWeek = 7; const int DaysInMonth = 30; var songs = new List<string> { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' }; var artists = new List<string> { 'ACDC', 'Led Zeppelin', 'The Beatles' }; bool EraseDatabase() {} bool RestoreDatabase() {} class Animal {} class Alpaca {}

⬆ back to top

</details> <details> <summary><b>Use pronounceable names</b></summary>

It will take time to investigate the meaning of the variables and functions when they are not pronounceable.

Bad:

public class Employee { public Datetime sWorkDate { get; set; } // what the heck is this public Datetime modTime { get; set; } // same here }

Good:

public class Employee { public Datetime StartWorkingDate { get; set; } public Datetime ModificationTime { get; set; } }

⬆ Back to top

</details> <details> <summary><b>Use Camelcase notation</b></summary>

Use Camelcase Notation for variable and method paramaters.

Bad:

var employeephone; public double CalculateSalary(int workingdays, int workinghours) { // some logic }

Good:

var employeePhone; public double CalculateSalary(int workingDays, int workingHours) { // some logic }

⬆ Back to top

</details> <details> <summary><b>Use domain name</b></summary>

People who read your code are also programmers. Naming things right will help everyone be on the same page. We don't want to take time to explain to everyone what a variable or function is for.

Good

public class SingleObject { // create an object of SingleObject private static SingleObject _instance = new SingleObject(); // make the constructor private so that this class cannot be instantiated private SingleObject() {} // get the only object available public static SingleObject GetInstance() { return _instance; } public string ShowMessage() { return "Hello World!"; } } public static void main(String[] args) { // illegal construct // var object = new SingleObject(); // Get the only object available var singletonObject = SingleObject.GetInstance(); // show the message singletonObject.ShowMessage(); }

⬆ Back to top

</details>

Variables

<details> <summary><b>Avoid nesting too deeply and return early</b></summary>

Too many if else statements can make the code hard to follow. Explicit is better than implicit.

Bad:

public bool IsShopOpen(string day) { if (!string.IsNullOrEmpty(day)) { day = day.ToLower(); if (day == "friday") { return true; } else if (day == "saturday") { return true; } else if (day == "sunday") { return true; } else { return false; } } else { return false; } }

Good:

public bool IsShopOpen(string day) { if (string.IsNullOrEmpty(day)) { return false; } var openingDays = new[] { "friday", "saturday", "sunday" }; return openingDays.Any(d => d == day.ToLower()); }

Bad:

public long Fibonacci(int n) { if (n < 50) { if (n != 0) { if (n != 1) { return Fibonacci(n - 1) + Fibonacci(n - 2); } else { return 1; } } else { return 0; } } else { throw new System.Exception("Not supported"); } }

Good:

public long Fibonacci(int n) { if (n == 0) { return 0; } if (n == 1) { return 1; } if (n > 50) { throw new System.Exception("Not supported"); } return Fibonacci(n - 1) + Fibonacci(n - 2); }

⬆ back to top

</details> <details> <summary><b>Avoid mental mapping</b></summary>

Don’t force the reader of your code to translate what the variable means. Explicit is better than implicit.

Bad:

var l = new[] { "Austin", "New York", "San Francisco" }; for (var i = 0; i < l.Count(); i++) { var li = l[i]; DoStuff(); DoSomeOtherStuff(); // ... // ... // ... // Wait, what is `li` for again? Dispatch(li); }

Good:

var locations = new[] { "Austin", "New York", "San Francisco" }; foreach (var location in locations) { DoStuff(); DoSomeOtherStuff(); // ... // ... // ... Dispatch(location); }

⬆ back to top

</details> <details> <summary><b>Avoid magic string</b></summary>

Magic strings are string values that are specified directly within application code that have an impact on the application’s behavior. Frequently, such strings will end up being duplicated within the system, and since they cannot automatically be updated using refactoring tools, they become a common source of bugs when changes are made to some strings but not others.

Bad

if (userRole == "Admin") { // logic in here }

Good

const string ADMIN_ROLE = "Admin" if (userRole == ADMIN_ROLE) { // logic in here }

Using this we only have to change in centralize place and others will adapt it.

⬆ back to top

</details> <details> <summary><b>Don't add unneeded context</b></summary>

If your class/object name tells you something, don't repeat that in your variable name.

Bad:

public class Car { public string CarMake { get; set; } public string CarModel { get; set; } public string CarColor { get; set; } //... }

Good:

public class Car { public string Make { get; set; } public string Model { get; set; } public string Color { get; set; } //... }

⬆ back to top

</details> <details> <summary><b>Use meaningful and pronounceable variable names</b></summary>

Bad:

var ymdstr = DateTime.UtcNow.ToString("MMMM dd, yyyy");

Good:

var currentDate = DateTime.UtcNow.ToString("MMMM dd, yyyy");

⬆ Back to top

</details> <details> <summary><b>Use the same vocabulary for the same type of variable</b></summary>

Bad:

GetUserInfo(); GetUserData(); GetUserRecord(); GetUserProfile();

Good:

GetUser();

⬆ Back to top

</details> <details> <summary><b>Use searchable names (part 1)</b></summary>

We will read more code than we will ever write. It's important that the code we do write is readable and searchable. By not naming variables that end up being meaningful for understanding our program, we hurt our readers. Make your names searchable.

Bad:

// What the heck is data for? var data = new { Name = "John", Age = 42 }; var stream1 = new MemoryStream(); var ser1 = new DataContractJsonSerializer(typeof(object)); ser1.WriteObject(stream1, data); stream1.Position = 0; var sr1 = new StreamReader(stream1); Console.Write("JSON form of Data object: "); Console.WriteLine(sr1.ReadToEnd());

Good:

var person = new Person { Name = "John", Age = 42 }; var stream2 = new MemoryStream(); var ser2 = new DataContractJsonSerializer(typeof(Person)); ser2.WriteObject(stream2, data); stream2.Position = 0; var sr2 = new StreamReader(stream2); Console.Write("JSON form of Data object: "); Console.WriteLine(sr2.ReadToEnd());

⬆ Back to top

</details> <details> <summary><b>Use searchable names (part 2)</b></summary>

Bad:

var data = new { Name = "John", Age = 42, PersonAccess = 4}; // What the heck is 4 for? if (data.PersonAccess == 4) { // do edit ... }

Good:

public enum PersonAccess : int { ACCESS_READ = 1, ACCESS_CREATE = 2, ACCESS_UPDATE = 4, ACCESS_DELETE = 8 } var person = new Person { Name = "John", Age = 42, PersonAccess= PersonAccess.ACCESS_CREATE }; if (person.PersonAccess == PersonAccess.ACCESS_UPDATE) { // do edit ... }

⬆ Back to top

</details> <details> <summary><b>Use explanatory variables</b></summary>

Bad:

const string Address = "One Infinite Loop, Cupertino 95014"; var cityZipCodeRegex = @"/^[^,\]+[,\\s]+(.+?)\s*(\d{5})?$/"; var matches = Regex.Matches(Address, cityZipCodeRegex); if (matches[0].Success == true && matches[1].Success == true) { SaveCityZipCode(matches[0].Value, matches[1].Value); }

Good:

Decrease dependence on regex by naming subpatterns.

const string Address = "One Infinite Loop, Cupertino 95014"; var cityZipCodeWithGroupRegex = @"/^[^,\]+[,\\s]+(?<city>.+?)\s*(?<zipCode>\d{5})?$/"; var matchesWithGroup = Regex.Match(Address, cityZipCodeWithGroupRegex); var cityGroup = matchesWithGroup.Groups["city"]; var zipCodeGroup = matchesWithGroup.Groups["zipCode"]; if(cityGroup.Success == true && zipCodeGroup.Success == true) { SaveCityZipCode(cityGroup.Value, zipCodeGroup.Value); }

⬆ back to top

</details> <details> <summary><b>Use default arguments instead of short circuiting or conditionals</b></summary>

Not good:

This is not good because breweryName can be NULL.

This opinion is more understandable than the previous version, but it better controls the value of the variable.

public void CreateMicrobrewery(string name = null) { var breweryName = !string.IsNullOrEmpty(name) ? name : "Hipster Brew Co."; // ... }

Good:

public void CreateMicrobrewery(string breweryName = "Hipster Brew Co.") { // ... }

⬆ back to top

</details>

Functions

<details> <summary><b>Avoid side effects</b></summary>

A function produces a side effect if it does anything other than take a value in and return another value or values. A side effect could be writing to a file, modifying some global variable, or accidentally wiring all your money to a stranger.

Now, you do need to have side effects in a program on occasion. Like the previous example, you might need to write to a file. What you want to do is to centralize where you are doing this. Don't have several functions and classes that write to a particular file. Have one service that does it. One and only one.

The main point is to avoid common pitfalls like sharing state between objects without any structure, using mutable data types that can be written to by anything, and not centralizing where your side effects occur. If you can do this, you will be happier than the vast majority of other programmers.

Bad:

// Global variable referenced by following function. // If we had another function that used this name, now it'd be an array and it could break

编辑推荐精选

Vora

Vora

免费创建高清无水印Sora视频

Vora是一个免费创建高清无水印Sora视频的AI工具

Refly.AI

Refly.AI

最适合小白的AI自动化工作流平台

无需编码,轻松生成可复用、可变现的AI自动化工作流

酷表ChatExcel

酷表ChatExcel

大模型驱动的Excel数据处理工具

基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。

AI工具酷表ChatExcelAI智能客服AI营销产品使用教程
TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
AIWritePaper论文写作

AIWritePaper论文写作

AI论文写作指导平台

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

AI辅助写作AI工具AI论文工具论文写作智能生成大纲数据安全AI助手热门
博思AIPPT

博思AIPPT

AI一键生成PPT,就用博思AIPPT!

博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。

AI办公办公工具AI工具博思AIPPTAI生成PPT智能排版海量精品模板AI创作热门
潮际好麦

潮际好麦

AI赋能电商视觉革命,一站式智能商拍平台

潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。

iTerms

iTerms

企业专属的AI法律顾问

iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。

SimilarWeb流量提升

SimilarWeb流量提升

稳定高效的流量提升解决方案,助力品牌曝光

稳定高效的流量提升解决方案,助力品牌曝光

Sora2视频免费生成

Sora2视频免费生成

最新版Sora2模型免费使用,一键生成无水印视频

最新版Sora2模型免费使用,一键生成无水印视频

下拉加载更多