### OCP: Implement Extension via Interface (C#) Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates the Open/Closed Principle by showing how to extend functionality without modifying existing code. The 'bad' example uses conditional logic, while the 'good' example uses an interface for extensibility. ```csharp abstract class AdapterBase { protected string Name; public string GetName() { return Name; } } class AjaxAdapter : AdapterBase { public AjaxAdapter() { Name = "ajaxAdapter"; } } class NodeAdapter : AdapterBase { public NodeAdapter() { Name = "nodeAdapter"; } } class HttpRequester : AdapterBase { private readonly AdapterBase Adapter; public HttpRequester(AdapterBase adapter) { Adapter = adapter; } public bool Fetch(string url) { var adapterName = Adapter.GetName(); if (adapterName == "ajaxAdapter") { return MakeAjaxCall(url); } else if (adapterName == "httpNodeAdapter") { return MakeHttpCall(url); } } private bool MakeAjaxCall(string url) { // request and return promise } private bool MakeHttpCall(string url) { // request and return promise } } ``` ```csharp interface IAdapter { bool Request(string url); } class AjaxAdapter : IAdapter { public bool Request(string url) { // request and return promise } } class NodeAdapter : IAdapter { public bool Request(string url) { // request and return promise } } class HttpRequester { private readonly IAdapter Adapter; public HttpRequester(IAdapter adapter) { Adapter = adapter; } public bool Fetch(string url) { return Adapter.Request(url); } } ``` -------------------------------- ### C# Composition Over Inheritance Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates the principle of preferring composition over inheritance in C# design. The example shows a 'Bad' approach using inheritance for unrelated concepts and a 'Good' approach using composition to model 'has-a' relationships effectively. ```csharp // Bad Example: Inheritance for unrelated concepts class Employee { private string Name { get; set; } private string Email { get; set; } public Employee(string name, string email) { Name = name; Email = email; } // ... } // Bad because Employees "have" tax data, not a type of Employee class EmployeeTaxData : Employee { private string Name { get; } private string Email { get; } public EmployeeTaxData(string name, string email, string ssn, string salary) { // ... } // ... } // Good Example: Using Composition class EmployeeTaxData { public string Ssn { get; } public string Salary { get; } public EmployeeTaxData(string ssn, string salary) { Ssn = ssn; Salary = salary; } // ... } class Employee { public string Name { get; } public string Email { get; } public EmployeeTaxData TaxData { get; } public Employee(string name, string email) { Name = name; Email = email; } public void SetTax(string ssn, double salary) { TaxData = new EmployeeTaxData(ssn, salary.ToString()); // Assuming salary is string for simplicity in example } // ... } ``` -------------------------------- ### C# Object-Oriented Programming Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Demonstrates object-oriented concepts in C# using base classes, derived classes, and method overriding. Includes examples of rendering different shapes based on their type. ```csharp public abstract class ShapeBase { protected double Width { get; set; } protected double Height { get; set; } public virtual double GetArea() { return Width * Height; } public virtual void Render(double area) { // Placeholder for rendering logic } } public class Rectangle : ShapeBase { public Rectangle(double width, double height) { Width = width; Height = height; } public double GetArea() { return Width * Height; } public void SetWidth(double width) { Width = width; } public void SetHeight(double height) { Height = height; } } public class Square : ShapeBase { private double Length = 0; public void SetLength(double length) { Length = length; } public double GetArea() { return Math.Pow(Length, 2); } } public class Drawable { // Placeholder for Drawable class } public static Drawable RenderLargeRectangles(IEnumerable rectangles) { foreach (var rectangle in rectangles) { if (rectangle is Square square) { square.SetLength(5); } else if (rectangle is Rectangle rect) { rect.SetWidth(4); rect.SetHeight(5); } var area = rectangle.GetArea(); rectangle.Render(area); } return null; // Placeholder return } // Usage example: // var shapes = new ShapeBase[] { new Rectangle(2, 3), new Rectangle(4, 5), new Square() }; // RenderLargeRectangles(shapes); ``` -------------------------------- ### Unit Test AAA Pattern Implementation Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates the 'Arrange-Act-Assert' (AAA) pattern for writing unit tests. It shows a 'Bad' example with multiple assertions in one test and a 'Good' example where each test focuses on a single concept, improving clarity and maintainability. ```csharp public class MakeDotNetGreatAgainTests { [Fact] public void Handle30DayMonths() { // Arrange var date = new MyDateTime("1/1/2015"); // Act date.AddDays(30); // Assert Assert.Equal("1/31/2015", date); } [Fact] public void HandleLeapYear() { // Arrange var date = new MyDateTime("2/1/2016"); // Act date.AddDays(28); // Assert Assert.Equal("02/29/2016", date); } [Fact] public void HandleNonLeapYear() { // Arrange var date = new MyDateTime("2/1/2015"); // Act date.AddDays(28); // Assert Assert.Equal("03/01/2015", date); } } ``` -------------------------------- ### JSON Serialization Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates serializing a C# object to JSON using DataContractJsonSerializer. This snippet shows how to properly handle streams and read the serialized output. ```csharp 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()); ``` -------------------------------- ### C# DI and Coupling Reduction: Bad vs Good Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates how Dependency Injection (DI) reduces coupling between classes. The 'Bad' example shows tight coupling to concrete types, while the 'Good' example uses an interface and collection for looser coupling, improving flexibility and maintainability. ```csharp public abstract class EmployeeBase { protected virtual void Work() { // .... } } public class Human : EmployeeBase { public override void Work() { // .... working much more } } public class Robot : EmployeeBase { public override void Work() { //.... working much, much more } } public class Manager { private readonly Robot _robot; private readonly Human _human; public Manager(Robot robot, Human human) { _robot = robot; _human = human; } public void Manage() { _robot.Work(); _human.Work(); } } ``` ```csharp public interface IEmployee { void Work(); } public class Human : IEmployee { public void Work() { // ....working } } public class Robot : IEmployee { public void Work() { //.... working much more } } public class Manager { private readonly IEnumerable _employees; public Manager(IEnumerable employees) { _employees = employees; } public void Manage() { foreach (var employee in _employees) { _employee.Work(); } } } ``` -------------------------------- ### Avoid global functions in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates the practice of avoiding global functions in C# to prevent namespace pollution and potential conflicts. The 'Bad' example shows a global configuration function, while the 'Good' example encapsulates configuration within a class, promoting better organization and dependency management. ```csharp public Dictionary Config() { return new Dictionary(){ ["foo"] = "bar" }; } ``` ```csharp class Configuration { private Dictionary _configuration; public Configuration(Dictionary configuration) { _configuration = configuration; } public string[] Get(string key) { return _configuration.ContainsKey(key) ? _configuration[key] : null; } } // Usage: var configuration = new Configuration(new Dictionary() { ["foo"] = "bar" }); ``` -------------------------------- ### C# Don't Repeat Yourself (DRY) Principle Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates the Don't Repeat Yourself (DRY) principle in C# by showing how to avoid code duplication through abstraction. The example highlights the need for a common method to handle similar data processing and rendering tasks. ```csharp // Bad Example: public class EmployeeData {} public class Developers {} public class ManagerData {} public class Manager {} public List ShowDeveloperList(Developers developers) { // Assume 'developer' is an iterable collection of developer objects // foreach (var developer in developers) // { // var expectedSalary = developer.CalculateExpectedSalary(); // var experience = developer.GetExperience(); // var githubLink = developer.GetGithubLink(); // var data = new[] { // expectedSalary, // experience, // githubLink // }; // Render(data); // } return null; // Placeholder } public List ShowManagerList(Manager managers) { // Assume 'manager' is an iterable collection of manager objects // foreach (var manager in managers) // { // var expectedSalary = manager.CalculateExpectedSalary(); // var experience = manager.GetExperience(); // var githubLink = manager.GetGithubLink(); // // ... similar data extraction and rendering logic ... // } return null; // Placeholder } // Placeholder for Render method // public void Render(object[] data) { } ``` -------------------------------- ### Use Domain Name for Clarity in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Naming things correctly helps programmers on the same page, reducing the need for explanations. This example demonstrates the Singleton design pattern using domain-specific naming like `SingleObject` and `GetInstance` for clear intent. ```csharp 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(); } ``` -------------------------------- ### SRP: Refactor Class for Single Responsibility (C#) Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates refactoring a class to adhere to the Single Responsibility Principle. Shows a 'bad' example with multiple responsibilities and a 'good' example separating concerns into distinct classes. ```csharp class UserSettings { private User User; public UserSettings(User user) { User = user; } public void ChangeSettings(Settings settings) { if (verifyCredentials()) { // ... } } private bool VerifyCredentials() { // ... } } ``` ```csharp class UserAuth { private User User; public UserAuth(User user) { User = user; } public bool VerifyCredentials() { // ... } } class UserSettings { private User User; private UserAuth Auth; public UserSettings(User user) { User = user; Auth = new UserAuth(user); } public void ChangeSettings(Settings settings) { if (Auth.VerifyCredentials()) { // ... } } } ``` -------------------------------- ### Functions Should Be One Level of Abstraction Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Explains that functions should operate at a single level of abstraction. The example demonstrates breaking down a complex parsing function into smaller, focused components (Tokenizer, Lexer) and using dependency injection for better modularity and testability. ```csharp class Tokenizer { public string Tokenize(string code) { var regexes = new string[] { // ... }; var statements = explode(" ", code); var tokens = new string[] {}; foreach (var regex in regexes) { foreach (var statement in statements) { tokens[] = /* ... */; } } return tokens; } } class Lexer { public string Lexify(string[] tokens) { var ast = new[] {}; foreach (var token in tokens) { ast[] = /* ... */; } return ast; } } class BetterJSAlternative { private Tokenizer _tokenizer; private Lexer _lexer; public BetterJSAlternative(Tokenizer tokenizer, Lexer lexer) { _tokenizer = tokenizer; _lexer = lexer; } public string Parse(string code) { var tokens = _tokenizer.Tokenize(code); var ast = _lexer.Lexify(tokens); foreach (var node in ast) { // parse... } } } ``` -------------------------------- ### Combine two integers in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates a simple C# method for combining two integer values through addition. This serves as a basic example of a single-responsibility function. ```csharp public int Combine(int val1, int val2) { return val1 + val2; } ``` -------------------------------- ### Function Names Should Say What They Do Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Highlights the importance of clear and descriptive function names. The example contrasts a vague `Handle()` method with a specific `Send()` method, making the code's intent immediately obvious. ```csharp public class Email { //... public void Handle() { SendMail(this._to, this._subject, this._body); } } var message = new Email(...); message.Handle(); // vs public class Email { //... public void Send() { SendMail(this._to, this._subject, this._body); } } var message = new Email(...); message.Send(); ``` -------------------------------- ### Avoid Singleton pattern in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Explains why the Singleton pattern is considered an anti-pattern in software development, citing issues with dependency hiding, single responsibility violation, tight coupling, and testability. The 'Bad' example shows a typical Singleton implementation, while the 'Good' example demonstrates dependency injection for managing object lifecycles. ```csharp class DBConnection { private static DBConnection _instance; private DBConnection() { // ... } public static GetInstance() { if (_instance == null) { _instance = new DBConnection(); } return _instance; } // ... } // Usage: var singleton = DBConnection.GetInstance(); ``` ```csharp class DBConnection { public DBConnection(IOptions options) { // ... } // ... } // Usage: var options = ; var connection = new DBConnection(options); ``` -------------------------------- ### C# Dependency Inversion Principle (DIP) Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Demonstrates the Dependency Inversion Principle in C# by decoupling high-level modules from low-level modules. It shows how depending on abstractions (interfaces) reduces coupling and improves testability. ```csharp // Bad Example: public abstract class EmployeeBaseBad { protected virtual void Work() { // ....working } } public class HumanBadDIP : EmployeeBaseBad { public override void Work() { //.... working much more } } public class RobotBadDIP : EmployeeBaseBad { public override void Work() { //.... working, much, much more } } public class ManagerBad { private readonly RobotBadDIP _robot; private readonly HumanBadDIP _human; public ManagerBad(RobotBadDIP robot, HumanBadDIP human) { _robot = robot; _human = human; } public void Manage() { _robot.Work(); _human.Work(); } } // Good Example: public interface IEmployee { void Work(); } public class HumanGoodDIP : IEmployee { public void Work() { // ....working } } public class RobotGoodDIP : IEmployee { public void Work() { //.... working much more } } public class ManagerGood { private readonly IEnumerable _employees; public ManagerGood(IEnumerable employees) { _employees = employees; } public void Manage() { foreach (var employee in _employees) { employee.Work(); } } } ``` -------------------------------- ### Good: Single Concept Per Test for Date Boundaries (C#) Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md This example illustrates the 'single concept per test' principle by separating each date boundary scenario into its own dedicated test method. This approach enhances clarity, isolation, and makes it easier to identify which specific scenario failed. ```csharp public class MakeDotNetGreatAgainTests { [Fact] public void Handle30DayMonths() { // Arrange var date = new MyDateTime("1/1/2015"); // Act date.AddDays(30); // Assert Assert.Equal("1/31/2015", date); } [Fact] public void HandleLeapYear() { // Arrange var date = new MyDateTime("2/1/2016"); // Act date.AddDays(28); // Assert Assert.Equal("02/29/2016", date); } [Fact] public void HandleNonLeapYear() { // Arrange var date = new MyDateTime("2/1/2015"); // Act date.AddDays(28); // Assert Assert.Equal("03/01/2015", date); } } ``` -------------------------------- ### C# DRY Principle: Avoiding Duplicate Code Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates the Don't Repeat Yourself (DRY) principle by refactoring duplicate code. The 'Bad' examples show repetitive logic for processing different employee types. The 'Good' and 'Very good' examples abstract this logic into a single method, reducing redundancy and improving maintainability. ```csharp public List ShowDeveloperList(Developers developers) { foreach (var developers in developer) { var expectedSalary = developer.CalculateExpectedSalary(); var experience = developer.GetExperience(); var githubLink = developer.GetGithubLink(); var data = new[] { expectedSalary, experience, githubLink }; Render(data); } } public List ShowManagerList(Manager managers) { foreach (var manager in managers) { var expectedSalary = manager.CalculateExpectedSalary(); var experience = manager.GetExperience(); var githubLink = manager.GetGithubLink(); var data = new[] { expectedSalary, experience, githubLink }; render(data); } } ``` ```csharp public List ShowList(Employee employees) { foreach (var employee in employees) { var expectedSalary = employees.CalculateExpectedSalary(); var experience = employees.GetExperience(); var githubLink = employees.GetGithubLink(); var data = new[] { expectedSalary, experience, githubLink }; render(data); } } ``` ```csharp public List ShowList(Employee employees) { foreach (var employee in employees) { render(new[] { employee.CalculateExpectedSalary(), employee.GetExperience(), employee.GetGithubLink() }); } } ``` -------------------------------- ### C# Getters and Setters for Encapsulation Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Demonstrates the use of getters and setters in C# to control access to object members, enforce encapsulation, and simplify property validation. It contrasts a 'Bad' example with direct public field access to a 'Good' example using private fields and public properties with methods for modification. ```csharp class BankAccount { public double Balance = 1000; } var bankAccount = new BankAccount(); // Fake buy shoes... bankAccount.Balance -= 100; ``` ```csharp class BankAccount { private double _balance = 0.0D; public double Balance { get { return _balance; } } public BankAccount(double balance = 1000) { _balance = balance; } public void WithdrawBalance(int amount) { if (amount > _balance) { throw new Exception('Amount greater than available balance.'); } _balance -= amount; } public void DepositBalance(int amount) { _balance += amount; } } var bankAccount = new BankAccount(); // Buy shoes... // bankAccount.WithdrawBalance(price); // Get balance // balance = bankAccount.Balance; ``` -------------------------------- ### C# Interface Segregation Good Example: Segregated Interfaces Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates the Interface Segregation Principle in C#. By creating smaller, role-specific interfaces (`IWorkable`, `IFeedable`), clients are only forced to depend on the methods they actually use. This leads to more cohesive and maintainable code. ```csharp public interface IWorkable { void Work(); } public interface IFeedable { void Eat(); } public interface IEmployee : IFeedable, IWorkable { } public class Human : IEmployee { public void Work() { // ....working } public void Eat() { //.... eating in lunch break } } // robot can only work public class Robot : IWorkable { public void Work() { // ....working } } ``` -------------------------------- ### Use Consistent Capitalization in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Consistent capitalization rules, chosen by a team, significantly improve code readability. This example contrasts inconsistent capitalization for constants, variables, methods, and classes with a consistent approach. ```csharp const int DAYS_IN_WEEK = 7; const int daysInMonth = 30; var songs = new List { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' }; var Artists = new List { 'ACDC', 'Led Zeppelin', 'The Beatles' }; bool EraseDatabase() {} bool Restore_database() {} class animal {} class Alpaca {} ``` ```csharp const int DaysInWeek = 7; const int DaysInMonth = 30; var songs = new List { 'Back In Black', 'Stairway to Heaven', 'Hey Jude' }; var artists = new List { 'ACDC', 'Led Zeppelin', 'The Beatles' }; bool EraseDatabase() {} bool RestoreDatabase() {} class Animal {} class Alpaca {} ``` -------------------------------- ### C# Function Proximity and Order Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates the principle of keeping calling and called functions close to each other in C# code. The example shows refactoring a class to place methods in a more readable, top-down order. ```csharp class PerformanceReview { private readonly Employee _employee; public PerformanceReview(Employee employee) { _employee = employee; } public PerfReviewData PerfReview() { GetPeerReviews(); GetManagerReview(); GetSelfReview(); } private IEnumerable GetPeerReviews() { var peers = LookupPeers(); // ... } private IEnumerable LookupPeers() { return db.lookup(_employee, 'peers'); } private ManagerData GetManagerReview() { var manager = LookupManager(); return manager; } private ManagerData LookupManager() { return db.lookup(_employee, 'manager'); } private EmployeeData GetSelfReview() { // ... } } var review = new PerformanceReview(employee); review.PerfReview(); ``` -------------------------------- ### C# .editorconfig for Consistent Code Formatting Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Provides an example `.editorconfig` file to enforce consistent code style across a C# project. It defines settings for indentation, line endings, whitespace, and new line preferences, preventing mixed formatting styles. ```csharp root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true # C# files [*.cs] indent_size = 4 # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_within_query_expression_clauses = true # Code files [*.{cs,csx,vb,vbx}] indent_size = 4 ``` -------------------------------- ### C# Composition Over Inheritance for Flexibility Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates the principle of favoring composition over inheritance for better design flexibility, as recommended by the Gang of Four. The 'Bad' example shows incorrect inheritance where an EmployeeTaxData is treated as a type of Employee. The 'Good' example demonstrates composition, where EmployeeTaxData is a member of the Employee class. ```csharp class Employee { private string Name { get; set; } private string Email { get; set; } public Employee(string name, string email) { Name = name; Email = email; } // ... } // Bad because Employees "have" tax data. // EmployeeTaxData is not a type of Employee class EmployeeTaxData : Employee { private string Name { get; } private string Email { get; } public EmployeeTaxData(string name, string email, string ssn, string salary) { // ... } // ... } ``` ```csharp class EmployeeTaxData { public string Ssn { get; } public string Salary { get; } public EmployeeTaxData(string ssn, string salary) { Ssn = ssn; Salary = salary; } // ... } class Employee { public string Name { get; } public string Email { get; } public EmployeeTaxData TaxData { get; } public Employee(string name, string email) { Name = name; Email = email; } public void SetTax(string ssn, double salary) { // TaxData = new EmployeeTaxData(ssn, salary); } // ... } ``` -------------------------------- ### Functions Should Do One Thing Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates the principle that functions should perform a single, well-defined action. The example shows refactoring a function that handles both filtering and sending emails into two separate, more manageable functions. ```csharp public void SendEmailToListOfClients(string[] clients) { var activeClients = GetActiveClients(clients); // Do some logic } public List GetActiveClients(string[] clients) { return db.Find(clients).Where(s => s.Status == "Active"); } ``` -------------------------------- ### C# Interface Segregation Principle (ISP) Example Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates the Interface Segregation Principle in C# by refactoring a monolithic `IEmployee` interface into smaller, more specific interfaces (`IWorkable`, `IFeedable`). This prevents clients from depending on methods they don't use. ```csharp // Bad Example: public interface IEmployeeBad { void Work(); void Eat(); } public class HumanBad : IEmployeeBad { public void Work() { // ....working } public void Eat() { // ...... eating in lunch break } } public class RobotBad : IEmployeeBad { public void Work() { //.... working much more } public void Eat() { //.... robot can't eat, but it must implement this method } } // Good Example: public interface IWorkable { void Work(); } public interface IFeedable { void Eat(); } public interface IEmployeeGood : IFeedable, IWorkable { } public class HumanGood : IEmployeeGood { public void Work() { // ....working } public void Eat() { //.... eating in lunch break } } // robot can only work public class RobotGood : IWorkable { public void Work() { // ....working } } ``` -------------------------------- ### Avoid Misleading Names in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Variables should be named to accurately reflect their purpose and content. This example shows how renaming `dataFromDb` to `listOfEmployee` clarifies the data source and type, improving code comprehension. ```csharp var dataFromDb = db.GetFromService().ToList(); ``` ```csharp var listOfEmployee = _employeeService.GetEmployees().ToList(); ``` -------------------------------- ### Use Searchable Variable Names in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Emphasizes the need for searchable variable names to aid code comprehension, as developers read more code than they write. This example shows how a vague 'data' variable hinders searchability compared to a more specific name. ```csharp // 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()); ``` -------------------------------- ### Use Meaningful and Pronounceable Variable Names in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Highlights the importance of using variable names that are both meaningful and easy to pronounce. This example contrasts a cryptic date format string variable with a clear, descriptive one. ```csharp var ymdstr = DateTime.UtcNow.ToString("MMMM dd, yyyy"); ``` ```csharp var currentDate = DateTime.UtcNow.ToString("MMMM dd, yyyy"); ``` -------------------------------- ### Bad: Testing Multiple Date Boundaries in One Test (C#) Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md This example demonstrates a test method that violates the 'single concept per test' principle by grouping multiple distinct date boundary scenarios into a single test, making it harder to read and maintain. ```csharp public class MakeDotNetGreatAgainTests { [Fact] public void HandleDateBoundaries() { var date = new MyDateTime("1/1/2015"); date.AddDays(30); Assert.Equal("1/31/2015", date); date = new MyDateTime("2/1/2016"); date.AddDays(28); Assert.Equal("02/29/2016", date); date = new MyDateTime("2/1/2015"); date.AddDays(28); Assert.Equal("03/01/2015", date); } } ``` -------------------------------- ### C# Removing Obsolete Code Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Shows the practice of removing unused or obsolete code from a C# codebase. The example refactors a class by removing a redundant method and renaming the active one to simplify usage. ```csharp public void RequestModule(string url) { // ... } var request = RequestModule(requestUrl); InventoryTracker("apples", request, "www.inventory-awesome.io"); ``` -------------------------------- ### C# Liskov Substitution Good Example: Shape Hierarchy Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Shows a correct implementation adhering to the Liskov Substitution Principle in C#. It uses an abstract `ShapeBase` class and separate `Rectangle` and `Square` classes, each with its own logic for calculating area, avoiding inheritance issues. ```csharp abstract class ShapeBase { protected double Width = 0; protected double Height = 0; abstract public double GetArea(); public Drawable Render(double area) { // ... } } class Rectangle : ShapeBase { public void SetWidth(double width) { Width = width; } public void SetHeight(double height) { Height = height; } public double GetArea() { return Width * Height; } } class Square : ShapeBase { private double Length = 0; public void SetLength(double length) { Length = length; } public double GetArea() { return Math.Pow(Length, 2); } } Drawable RenderLargeRectangles(ShapeBase[] shapes) { foreach (var shape in shapes) { if (shape is Square square) { square.SetLength(5); } else if (shape is Rectangle rectangle) { rectangle.SetWidth(4); rectangle.SetHeight(5); } var area = shape.GetArea(); shape.Render(area); } } var shapes = new ShapeBase[] { new Rectangle(), new Rectangle(), new Square() }; RenderLargeRectangles(shapes); ``` -------------------------------- ### C# Fluent Interface for List Operations Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Provides an example of using a fluent interface pattern with extension methods for C# Lists. This allows for method chaining, making code more readable and expressive. It includes methods for adding, inserting, removing, reversing, iterating, and clearing the list. ```csharp public static class ListExtensions { public static List FluentAdd(this List list, T item) { list.Add(item); return list; } public static List FluentClear(this List list) { list.Clear(); return list; } public static List FluentForEach(this List list, Action action) { list.ForEach(action); return list; } public static List FluentInsert(this List list, int index, T item) { list.Insert(index, item); return list; } public static List FluentRemoveAt(this List list, int index) { list.RemoveAt(index); return list; } public static List FluentReverse(this List list) { list.Reverse(); return list; } } internal static void ListFluentExtensions() { var list = new List() { 1, 2, 3, 4, 5 } .FluentAdd(1) .FluentInsert(0, 0) .FluentRemoveAt(1) .FluentReverse() .FluentForEach(value => Console.WriteLine(value)) .FluentClear(); } ``` -------------------------------- ### Use Camel Case Notation in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Camel case notation is recommended for variable and method parameters to improve readability. This example contrasts a variable `employeephone` and parameters `workingdays`, `workinghours` with their camel-cased counterparts `employeePhone`, `workingDays`, `workingHours`. ```csharp var employeephone; public double CalculateSalary(int workingdays, int workinghours) { // some logic } ``` ```csharp var employeePhone; public double CalculateSalary(int workingDays, int workingHours) { // some logic } ``` -------------------------------- ### C# Interface Segregation Bad Example: Fat Employee Interface Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates a violation of the Interface Segregation Principle in C#. The `IEmployee` interface forces both `Human` and `Robot` classes to implement methods they don't need (e.g., `Eat` for `Robot`), leading to unnecessary implementation and potential errors. ```csharp public interface IEmployee { void Work(); void Eat(); } public class Human : IEmployee { public void Work() { // ....working } public void Eat() { // ...... eating in lunch break } } public class Robot : IEmployee { public void Work() { //.... working much more } public void Eat() { //.... robot can't eat, but it must implement this method } ``` -------------------------------- ### C# Liskov Substitution Bad Example: Square-Rectangle Inheritance Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates a violation of the Liskov Substitution Principle using C# inheritance. A Square class inherits from Rectangle, leading to incorrect behavior when substituting a Square for a Rectangle in operations like setting dimensions and calculating area. ```csharp class Rectangle { protected double Width = 0; protected double Height = 0; public Drawable Render(double area) { // ... } public void SetWidth(double width) { Width = width; } public void SetHeight(double height) { Height = height; } public double GetArea() { return Width * Height; } } class Square : Rectangle { public void SetWidth(double width) { Width = Height = width; } public void SetHeight(double height) { Width = Height = height; } } Drawable RenderLargeRectangles(Rectangle rectangles) { foreach (var rectangle in rectangles) { rectangle.SetWidth(4); rectangle.SetHeight(5); var area = rectangle.GetArea(); // BAD: Will return 25 for Square. Should be 20. rectangle.Render(area); } } var rectangles = new[] { new Rectangle(), new Rectangle(), new Square() }; RenderLargeRectangles(rectangles); ``` -------------------------------- ### Async/Await Best Practices Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Key guidelines for effective asynchronous programming in C#, including avoiding async void, adopting 'async all the way', and proper context configuration. ```APIDOC Async/Await Guidelines: - Avoid async void: Prefer async Task methods over async void methods, except for event handlers. - Async all the way: Do not mix blocking and asynchronous code; maintain consistency throughout the call stack. - Configure context: Use `ConfigureAwait(false)` in library code to prevent deadlocks and improve performance when context is not required. ``` -------------------------------- ### Use Default Arguments Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates how to use default parameter values in method signatures instead of conditional logic or short-circuiting expressions. This simplifies method bodies and makes the default behavior explicit. ```csharp public void CreateMicrobrewery(string breweryName = "Hipster Brew Co.") { // ... } ``` -------------------------------- ### C# Tokenizer and Lexer Implementation Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Demonstrates the implementation of Tokenizer and Lexer classes in C# for parsing code. It shows how to break down code into tokens and then build an Abstract Syntax Tree (AST). ```csharp class Tokenizer { public string Tokenize(string code) { var regexes = new string[] { // ... }; var statements = explode(" ", code); var tokens = new string[] {}; foreach (var regex in regexes) { foreach (var statement in statements) { tokens[] = /* ... */; } } return tokens; } } class Lexer { public string Lexify(string[] tokens) { var ast = new[] {}; foreach (var token in tokens) { ast[] = /* ... */; } return ast; } } class BetterJSAlternative { private string _tokenizer; private string _lexer; public BetterJSAlternative(Tokenizer tokenizer, Lexer lexer) { _tokenizer = tokenizer; _lexer = lexer; } public string Parse(string code) { var tokens = _tokenizer.Tokenize(code); var ast = _lexer.Lexify(tokens); foreach (var node in ast) { // parse... } } } ``` -------------------------------- ### Avoid boolean flags in C# method parameters Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates how to refactor a C# method that uses a boolean flag to indicate different responsibilities. The 'Bad' example shows a method with a flag, while the 'Good' example splits it into two distinct methods for better clarity and single responsibility. ```csharp public void CreateFile(string name, bool temp = false) { if (temp) { Touch("./temp/" + name); } else { Touch(name); } } ``` ```csharp public void CreateFile(string name) { Touch(name); } public void CreateTempFile(string name) { Touch("./temp/" + name); } ``` -------------------------------- ### C# Private/Protected Members for Object Integrity Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates how to enforce object integrity by making members private or protected. The 'Bad' example shows a public property allowing direct modification, while the 'Good' example uses a read-only property and suggests methods for interaction, promoting better encapsulation. ```csharp class Employee { public string Name { get; set; } public Employee(string name) { Name = name; } } var employee = new Employee('John Doe'); Console.WriteLine(employee.Name) // Employee name: John Doe ``` ```csharp class Employee { public string Name { get; } public Employee(string name) { Name = name; } public string GetName() { return Name; } } var employee = new Employee('John Doe'); Console.WriteLine(employee.GetName());// Employee name: John Doe ``` -------------------------------- ### Use Searchable Names with Enums Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Illustrates the importance of using searchable and descriptive names, particularly by leveraging enums for magic numbers. This improves code readability and maintainability by making intent clear. ```csharp 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 ... } ``` -------------------------------- ### C# Method Chaining for Fluent Interfaces Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates how to implement method chaining in C# using extension methods to create fluent APIs. This pattern enhances code readability and reduces verbosity by allowing multiple operations to be called sequentially on an object. ```csharp public static class ListExtensions { public static List FluentAdd(this List list, T item) { list.Add(item); return list; } public static List FluentClear(this List list) { list.Clear(); return list; } public static List FluentForEach(this List list, Action action) { list.ForEach(action); return list; } public static List FluentInsert(this List list, int index, T item) { list.Insert(index, item); return list; } public static List FluentRemoveAt(this List list, int index) { list.RemoveAt(index); return list; } public static List FluentReverse(this List list) { list.Reverse(); return list; } } internal static void ListFluentExtensions() { var list = new List() { 1, 2, 3, 4, 5 } .FluentAdd(1) .FluentInsert(0, 0) .FluentRemoveAt(1) .FluentReverse() .FluentForEach(value => value.WriteLine()) .FluentClear(); } ``` -------------------------------- ### Use foreach and Meaningful Names in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Illustrates using `foreach` loops and descriptive variable names over indexed `for` loops. Enhances code clarity and intent by making iteration more readable. ```csharp 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); } ``` ```csharp var locations = new[] { "Austin", "New York", "San Francisco" }; foreach (var location in locations) { DoStuff(); DoSomeOtherStuff(); // ... // ... // ... Dispatch(location); } ``` -------------------------------- ### Use Explanatory Variables with Regex Groups Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Shows how to improve code clarity by using explanatory variables, especially when dealing with complex operations like regular expressions. Naming regex subpatterns makes the extraction logic more understandable. ```csharp const string Address = "One Infinite Loop, Cupertino 95014"; var cityZipCodeWithGroupRegex = @"/^[^,\\]+[[,\\s]+(?.+?)\s*(?\\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); } ``` -------------------------------- ### Avoid Deep Nesting and Return Early in C# Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README.md Demonstrates how to refactor deeply nested conditional logic into a cleaner structure using early returns and collection-based checks. This improves readability and reduces cognitive load. ```csharp 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; } } ``` ```csharp public bool IsShopOpen(string day) { if (string.IsNullOrEmpty(day)) { return false; } var openingDays = new[] { "friday", "saturday", "sunday" }; return openingDays.Any(d => d == day.ToLower()); } ``` -------------------------------- ### Code Formatting: .editorconfig for C# Projects Source: https://github.com/thangchung/clean-code-dotnet/blob/master/README-zh.md Demonstrates the use of a .editorconfig file to enforce consistent code style across a .NET project. It covers indentation, line endings, whitespace, and naming conventions for C# files. ```editorconfig root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true # C# files [*.cs] indent_size = 4 # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_within_query_expression_clauses = true # Code files [*.{cs,csx,vb,vbx}] indent_size = 4 # Indentation preferences csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true csharp_indent_switch_labels = true csharp_indent_labels = one_less_than_current # avoid this. unless absolutely necessary dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_event = false:suggestion # only use var when it's obvious what the variable type is # csharp_style_var_for_built_in_types = false:none # csharp_style_var_when_type_is_apparent = false:none # csharp_style_var_elsewhere = false:suggestion # use language keywords instead of BCL types dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion # name all constant fields using PascalCase dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.pascal_case_style.capitalization = pascal_case ```