适用于.NET/.NET核心的清洁代码概念
如果您喜欢clean-code-dotnet项目,或者如果对您有所帮助,请为此存储库提供一颗星。这不仅将有助于加强我们的.NET社区,而且还可以提高世界各地.NET开发人员的清洁代码技能。非常感谢?
查看我的博客或在Twitter上打招呼!
目录
- 适用于.NET/.NET核心的清洁代码概念
- 目录
- 介绍
- 清洁代码.NET
- 命名
- 变量
- 功能
- 对象和数据结构
- 课程
- 坚硬的
- 测试
- 并发
- 错误处理
- 格式化
- 评论
- 其他干净的代码资源
- 贡献者
- 支持者
- 赞助商
- 执照
介绍
罗伯特·马丁( Robert C.这不是样式指南。它是在.NET/.NET Core中生产可读,可重复使用和可重构软件的指南。
并非必须严格遵循此处的所有原则,甚至更少会被普遍同意。这些是准则,仅此而已,但是它们是在多年的集体经验中由清洁代码的集体经验编纂的。
灵感来自清洁代码javaScript和Clean-ode-PHP列表。
清洁代码.NET
命名
避免使用坏名称
好名字允许许多开发人员使用代码。名称应反映其所做的事情并给出上下文。
坏的:
int d ;
好的:
int daySinceModification ;
⬆回到顶部
避免误导名称
命名变量以反映其使用的用途。
坏的:
var dataFromDb = db . GetFromService ( ) . ToList ( ) ;
好的:
var listOfEmployee = _employeeService . GetEmployees ( ) . ToList ( ) ;
⬆回到顶部
避免匈牙利符号
匈牙利符号重述了声明中已经存在的类型。这是毫无意义的,因为现代IDE将识别类型。
坏的:
int iCounter ; string strFullName ; DateTime dModifiedDate ;
好的:
int counter ; string fullName ; DateTime modifiedDate ;
匈牙利符号也不应在参数术中使用。
坏的:
public bool IsShopOpen ( string pDay , int pAmount ) { // some logic }
好的:
public bool IsShopOpen ( string day , int amount ) { // some logic }
⬆回到顶部
使用一致的资本化
资本化告诉您有关您的变量,功能等的很多信息。这些规则是主观的,因此您的团队可以选择他们想要的任何东西。关键是,无论您选择什么,都保持一致。
坏的:
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 { }
好的:
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 { }
⬆回到顶部
使用明显的名称
当变量不可发音时,研究变量和函数的含义将需要时间。
坏的:
public class Employee { public Datetime sWorkDate { get ; set ; } // what the heck is this public Datetime modTime { get ; set ; } // same here }
好的:
public class Employee { public Datetime StartWorkingDate { get ; set ; } public Datetime ModificationTime { get ; set ; } }
⬆回到顶部
使用骆驼箱符号
使用骆驼箱表示法进行可变和方法参数。
坏的:
var employeephone ; public double CalculateSalary ( int workingdays , int workinghours ) { // some logic }
好的:
var employeePhone ; public double CalculateSalary ( int workingDays , int workingHours ) { // some logic }
⬆回到顶部
使用域名
阅读您的代码的人也是程序员。正确命名的事情将帮助每个人在同一页面上。我们不想花时间向所有人解释变量或函数的目的。
好的
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 ( ) ; }
⬆回到顶部
变量
避免筑巢太深并提早返回
如果其他语句可以使代码难以遵循,太多了。明确胜于隐式。
坏的:
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 ; } }
好的:
public bool IsShopOpen ( string day ) { if ( string . IsNullOrEmpty ( day ) ) { return false ; } var openingDays = new [ ] { \"friday\" , \"saturday\" , \"sunday\" } ; return openingDays . Any ( d => d == day . ToLower ( ) ) ; }
坏的:
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\" ) ; } }
好的:
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 ) ; }
⬆回到顶部
避免心理映射
不要强迫代码的读者转换变量的含义。明确胜于隐式。
坏的:
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 ) ; }
好的:
var locations = new [ ] { \"Austin\" , \"New York\" , \"San Francisco\" } ; foreach ( var location in locations ) { DoStuff ( ) ; DoSomeOtherStuff ( ) ; // ... // ... // ... Dispatch ( location ) ; }
⬆回到顶部
避免魔术弦
魔术字符串是直接在应用程序代码中指定的字符串值,对应用程序的行为产生影响。通常,这样的字符串最终会在系统中重复,并且由于无法使用重构工具自动更新它们,因此当对某些字符串进行更改而不是其他字符串进行更改时,它们成为常见的错误来源。
坏的
if ( userRole == \"Admin\" ) { // logic in here }
好的
const string ADMIN_ROLE = \"Admin\" if ( userRole == ADMIN_ROLE ) { // logic in here }
使用此功能,我们只需要在集中化的地方进行更改,而其他人则将对其进行调整。
⬆回到顶部
不要添加不必要的上下文
如果您的类/对象名称告诉您一些事情,请不要在变量名称中重复此操作。
坏的:
public class Car { public string CarMake { get ; set ; } public string CarModel { get ; set ; } public string CarColor { get ; set ; } //... }
好的:
public class Car { public string Make { get ; set ; } public string Model { get ; set ; } public string Color { get ; set ; } //... }
⬆回到顶部
使用有意义且明显的变量名称
坏的:
var ymdstr = DateTime . UtcNow . ToString ( \"MMMM dd, yyyy\" ) ;
好的:
var currentDate = DateTime . UtcNow . ToString ( \"MMMM dd, yyyy\" ) ;
⬆回到顶部
使用相同的词汇进行相同类型的变量
坏的:
GetUserInfo ( ) ; GetUserData ( ) ; GetUserRecord ( ) ; GetUserProfile ( ) ;
好的:
GetUser ( ) ;
⬆回到顶部
使用可搜索的名称(第1部分)
我们将读取的代码超出我们将要写的代码。重要的是,我们编写的代码是可以读取且可搜索的。通过不命名最终对于理解我们的计划有意义的变量,我们伤害了读者。使您的名字可搜索。
坏的:
// 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 ( ) ) ;
好的:
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 ( ) ) ;
⬆回到顶部
使用可搜索的名称(第2部分)
坏的:
var data = new { Name = \"John\" , Age = 42 , PersonAccess = 4 } ; // What the heck is 4 for? if ( data . PersonAccess == 4 ) { // do edit ... }
好的:
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 ... }
⬆回到顶部
使用解释变量
坏的:
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 ) ; }
好的:
通过命名子图案降低对正则对等级的依赖。
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 ) ; }
⬆回到顶部
使用默认参数代替短路或有条件的参数
不好:
这不是很好,因为breweryName可能为NULL 。
该意见比以前的版本更容易理解,但是它可以更好地控制变量的价值。
public void CreateMicrobrewery ( string name = null ) { var breweryName = ! string . IsNullOrEmpty ( name ) ? name : \"Hipster Brew Co.\" ; // ... }
好的:
public void CreateMicrobrewery ( string breweryName = \"Hipster Brew Co.\" ) { // ... }
⬆回到顶部
功能
避免副作用
如果函数在占据值并返回其他值或值之外,则会产生副作用。副作用可能是写入文件,修改某些全局变量,或者将所有资金意外地接线到陌生人。
现在,您有时需要在程序中产生副作用。像上一个示例一样,您可能需要写入文件。您想做的是集中您在哪里做。没有写入特定文件的几个功能和类。有一项服务。一个也是一个。
要点是避免使用可以用任何结构的物体之间的对象之间共享状态,使用任何可以写入任何事物的可变数据类型,而不是集中副作用发生的位置。如果您可以做到这一点,那么您将比其他绝大多数程序员更快乐。
坏的:
// 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 it.
var name = \"Ryan McDermott\" ;public void SplitAndEnrichFullName ( )
{
var temp = name . Split ( \" \" ) ;
name = $ \"His first name is { temp [ 0 ] } , and his last name is { temp <span class=\"pl-k
