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!

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.
Bad:
int d;
Good:
</details> <details> <summary><b>Avoid Misleading Names</b></summary>int daySinceModification;
Name the variable to reflect what it is used for.
Bad:
var dataFromDb = db.GetFromService().ToList();
Good:
</details> <details> <summary><b>Avoid Hungarian notation</b></summary>var listOfEmployee = _employeeService.GetEmployees().ToList();
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:
</details> <details> <summary><b>Use consistent capitalization</b></summary>public bool IsShopOpen(string day, int amount) { // some logic }
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:
</details> <details> <summary><b>Use pronounceable names</b></summary>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 {}
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:
</details> <details> <summary><b>Use Camelcase notation</b></summary>public class Employee { public Datetime StartWorkingDate { get; set; } public Datetime ModificationTime { get; set; } }
Use Camelcase Notation for variable and method paramaters.
Bad:
var employeephone; public double CalculateSalary(int workingdays, int workinghours) { // some logic }
Good:
</details> <details> <summary><b>Use domain name</b></summary>var employeePhone; public double CalculateSalary(int workingDays, int workingHours) { // some logic }
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
</details>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(); }
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:
</details> <details> <summary><b>Avoid mental mapping</b></summary>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); }
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:
</details> <details> <summary><b>Avoid magic string</b></summary>var locations = new[] { "Austin", "New York", "San Francisco" }; foreach (var location in locations) { DoStuff(); DoSomeOtherStuff(); // ... // ... // ... Dispatch(location); }
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.
</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:
</details> <details> <summary><b>Use meaningful and pronounceable variable names</b></summary>public class Car { public string Make { get; set; } public string Model { get; set; } public string Color { get; set; } //... }
Bad:
var ymdstr = DateTime.UtcNow.ToString("MMMM dd, yyyy");
Good:
</details> <details> <summary><b>Use the same vocabulary for the same type of variable</b></summary>var currentDate = DateTime.UtcNow.ToString("MMMM dd, yyyy");
Bad:
GetUserInfo(); GetUserData(); GetUserRecord(); GetUserProfile();
Good:
</details> <details> <summary><b>Use searchable names (part 1)</b></summary>GetUser();
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:
</details> <details> <summary><b>Use searchable names (part 2)</b></summary>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());
Bad:
var data = new { Name = "John", Age = 42, PersonAccess = 4}; // What the heck is 4 for? if (data.PersonAccess == 4) { // do edit ... }
Good:
</details> <details> <summary><b>Use explanatory variables</b></summary>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 ... }
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.
</details> <details> <summary><b>Use default arguments instead of short circuiting or conditionals</b></summary>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); }
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:
</details>public void CreateMicrobrewery(string breweryName = "Hipster Brew Co.") { // ... }
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


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


最适合小白的AI自动化工作流平台
无需编码,轻松生成可复用、可变现的AI自动化工作流

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


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


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


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


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


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


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


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