适用于.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]+(?.+?)s*(? ; 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 ) ; }d{5})?$/"
⬆回到顶部
使用默认参数代替短路或有条件的参数
不好:
这不是很好,因为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
下载源码
通过命令行克隆项目:
git clone https://github.com/thangchung/clean-code-dotnet.git