깨끗하고 읽기 쉽고 이해할 수 있으며 관리 가능한 C# 코드를 작성하기위한 대부분 합리적인 가이드 라인 및 모범 사례 모음.
var 사용하십시오목적 : 더 나은 가독성과 청결
좋은
var httpClient = new HttpClient ( ) ;나쁜
HttpClient httpClient = new HttpClient ( ) ; 목적 : 더 나은 가독성과 청결
좋은
var user = new User
{
Username = "admin" ,
Age = 31
} ;나쁜
var user = new User ( ) ;
user . Username = "admin" ;
user . Age = 31 ; string.Format 대신 문자열 보간을 사용하십시오목적 : 더 나은 가독성과 의미론
좋은
var url = "http://localhost/api" ;
var resource = "users" ;
var path = $ " { url } / { resource } " ;나쁜
var url = "http://localhost/api" ;
var resource = "users" ;
var path = string . Format ( "{0}/{1}" , url , resource ) ;목적 : 백 슬래시 캐릭터를 피할 필요가 없습니다
좋은
var path = @"C:UsersAdministratorDocuments" ;나쁜
var path = "C: \ Users \ Administrator \ Documents" ;목적 : 문자열 리터럴이 여러 번 배포되면 리팩토링이 악몽이 될 수 있습니다.
좋은
const string error = "user_not_found" ;
Log . Error ( error ) ;
return BadRequest ( error ) ;나쁜
Log . Error ( "user_not_found" ) ;
return BadRequest ( "user_not_found" ) ; xyz 의 이름을 지정하여 시간을 절약한다고 말하지 마십시오. 그것은 단지 우스운 일입니다.목적 : 변수 이름 단축 값은 값을 추가하지 않으며 코드를 읽고 이해하기가 더 어려워집니다.
좋은
// Nice
var validationResult = validator . Validate ( ) ;
// Nice
var stringBuilder = new StringBuilder ( ) ;
// Nice
const string directorySeparator = "/" ;나쁜
//
var res = validator . Validate ( ) ;
//
var sbd = new StringBuilder ( ) ;
// Seriously?
const string dsep = "/" ;목적 : 코드를 엄청나게 읽고, 유지 관리하고,
좋은
// The purpose of this class can be easily inferred
public class OrderManager
{
// Using "Is" or "Has" as prefix clearly indicates that a method returns a boolean value
public bool IsFulfilled ( Order order )
{
}
public bool HasPositions ( Order order )
{
}
// Using a verb clearly indicates that a method performs some action
public void ProcessOrder ( Order order )
{
}
public void CancelOrder ( Order order )
{
}
}나쁜
// Purpose of this class can not be easily inferred
public class OrderHelper
{
// Unclear
public bool Fulfilled ( Order order )
{
}
// Unclear => users would likely expect a method that retrieves the positions of the order due to the verb "Get"
public bool GetPositions ( Order order )
{
}
// Unclear
public void Order ( Order order )
{
}
// Unclear
public void StopOrder ( Order order )
{
}
}목적 : 코드를 불필요하게 더 길고 읽고 이해하기가 더 어려워집니다.
좋은
// Clearly an interface
public interface IOrderManager { }
// Clearly a list of orders
private IList < Order > orders ;나쁜
// Clearly an interface => no "Interface" postfix necessary
public interface IOrderManagerInterface { }
// Clearly a list of oders => no "List" postfix necessary
private IList < Order > orderList ;목적 : 관행은 코드 기반이 성장하고 진화함에 따라 주석이 매우 쉽고 빠르게 구제 될 수 있음을 보여줍니다. 자체 설명 코드 기반을 갖는 것은 더 나은 유지 관리에 기여하며 불안정한 의견을 작성하고 유지해야 할 필요성을 줄입니다. (이것은 댓글 작성이 쓸모 없다는 것을 의미하지는 않습니다.)
좋은
public class OrderManager
{
public void ProcessOrder ( Order order )
{
var items = order . GetItems ( ) ;
foreach ( var item in items )
{
var availability = item . GetAvailability ( ) ;
}
}
}나쁜
public class OrderManager
{
public void ExecuteOrder ( Order order )
{
// Get all available items from the order
var data = order . GetData ( ) ;
foreach ( var x in data )
{
// Determine the availability of the item
var available = item . CheckAvailability ( ) ;
}
}
}목적 : .NET 프레임 워크와 일치하고 읽기 쉬운
좋은
public class JsonParser { }나쁜
public class JSONParser { } 목적 : enum 는 항상 개별적으로 해결됩니다. 예를 들어 EmploymentType.FullTime 은 EmploymentTypes.FullTime 보다 훨씬 깨끗합니다. 또한 클래스는 항상 개별 User 와 같은 단일 인스턴스를 나타냅니다. 예외 : 비트 필드 열거
좋은
public enum EmploymentType
{
FullTime ,
PartTime
}
public class User
{
}나쁜
public enum EmploymentTypes
{
FullTime ,
PartTime
}
public class Users
{
} 목적 : 구문 설탕 ¯ (ツ) /¯
좋은
public class User
{
public string Username { get ; }
public int Age { get ; }
public string DisplayName => $ " { Username } ( { Age } )" ;
public User ( string username , int age )
{
Username = username ;
Age = age ;
}
}나쁜
public class User
{
public string Username { get ; }
public int Age { get ; }
public string DisplayName
{
get
{
return $ " { Username } ( { Age } )" ;
}
}
public User ( string username , int age )
{
Username = username ;
Age = age ;
}
} 목적 : 무엇이 잘못되었는지에 대한 더 나은 인식. 로깅 및 오류 분석 중에 더 많은 정밀도를 허용합니다.
좋은
try
{
System . IO . File . Open ( path ) ;
}
catch ( FileNotFoundException ex )
{
// Specific
}
catch ( IOException ex )
{
// Specific
}
catch ( Exception ex )
{
// Default
}나쁜
try
{
System . IO . File . Open ( path ) ;
}
catch ( Exception ex )
{
// SOMETHING went wrong
}Exception 사용하십시오. 목적 : 매우 나쁜 연습. Exception 는 .NET 프레임 워크에 의해서만 던져야합니다.
좋은
public void ProcessOrder ( Order order )
{
if ( order == null )
{
throw new ArgumentNullException ( nameof ( order ) ) ;
}
}나쁜
public void ProcessOrder ( Order order )
{
if ( order == null )
{
throw new Exception ( "Order is null." ) ;
}
} 목적 : 더 나은 가독성
좋은
private string _username ;나쁜
private string mUsername__ ;
// OR
private string username ;
// OR
private string username_ ; 목적 : 가독성이 향상되고 공간을 절약합니다
좋은
public class JsonParser
{
private readonly string _json ;
public JsonParser ( string json )
{
_json = json ;
}
}나쁜
public class JsonParser
{
private readonly string _json ;
public JsonParser ( string json )
{
_json = json ;
}
} 목적 : 부동산이 실수로 다른 곳에서 변경되는 것을 방지, 응용 프로그램의 행동에 대한 더 나은 예측
좋은
public class JsonParser
{
public string Json { get ; }
public JsonParser ( string json )
{
Json = json ;
}
}나쁜
public class JsonParser
{
public string Json { get ; set ; }
public JsonParser ( string json )
{
Json = json ;
}
}목적 : 컬렉션이 다른 곳에서 변경되는 것을 방지하고 응용 프로그램의 행동에 대한 더 나은 예측
좋은
public class KeywordProvider
{
public IReadOnlyCollection < string > Keywords { get ; }
public KeywordProvider ( )
{
Keywords = new ReadOnlyCollection < string > ( new List < string >
{
"public" ,
"string"
} ) ;
}
}나쁜
public class KeywordProvider
{
public IList < string > Keywords { get ; }
public KeywordProvider ( )
{
Keywords = new List < string >
{
"public" ,
"string"
} ;
}
} using 사용하십시오 목적 : using 블록이 완료되면 자원이 자동으로 폐기됩니다.
좋은
using ( var connection = new SqlConnection ( connectionString ) )
{
}나쁜
try
{
var connection = new SqlConnection ( connectionString ) ;
}
finally
{
connection . Close ( ) ;
connection . Dispose ( ) ;
} 목적 : 가독성 향상, 다른 라인이 조건 내에서 다른 라인이 필요할 때 쉬운 유지 보수
좋은
if ( user . IsElevated )
{
// Do something
}나쁜
if ( user . IsElevated )
// Do something목적 : 메시지의 어떤 부분에 변수가 포함되어 있는지 알 수 있습니다.
좋은
var filePath = @"C:tmpmy-file.txt" ;
try
{
var file = File . Open ( filePath ) ;
}
catch ( Exception ex )
{
// GOOD: Add [ ] to the variable
Log . Error ( $ "Could not open file [ { filePath } ]." , ex ) ;
}나쁜
var filePath = @"C:tmpmy-file.txt" ;
try
{
var file = File . Open ( filePath ) ;
}
catch ( Exception ex )
{
Log . Error ( $ "Could not open file { filePath } ." , ex ) ;
}목적 : 특정 경우에 예외를 필터링 할 수 있도록 (예 : 전체 스택 추적이 사용자에게는 쓸모가 없기 때문에 사용자 인터페이스에서와 같이).
좋은
try
{
var file = File . Open ( @"C:tmpmy-file.txt" ) ;
}
catch ( Exception ex )
{
// Use appropriate signature of your logger to include the exception as separate parameter
Log . Error ( "Could not open file." , ex ) ;
}나쁜
try
{
var file = File . Open ( @"C:tmpmy-file.txt" ) ;
}
catch ( Exception ex )
{
// Strictly AVOID this. The exception is added directly to the log message, which makes it impossible to filter the exception
Log . Error ( $ "Could not open file: { ex } " ) ;
}