{"id":17067726,"url":"https://github.com/justinamiller/dotnet-coding-guidelines","last_synced_at":"2025-04-06T13:12:06.941Z","repository":{"id":52845715,"uuid":"338357290","full_name":"justinamiller/DotNet-Coding-Guidelines","owner":"justinamiller","description":"This repo highlights the list of software engineering guidelines in general.","archived":false,"fork":false,"pushed_at":"2022-08-14T09:37:46.000Z","size":169,"stargazers_count":324,"open_issues_count":1,"forks_count":40,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-03-30T12:08:01.093Z","etag":null,"topics":["csharp","dotnet","engineering-guidelines"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/justinamiller.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-02-12T15:30:18.000Z","updated_at":"2025-02-25T23:12:32.000Z","dependencies_parsed_at":"2022-08-22T23:30:43.068Z","dependency_job_id":null,"html_url":"https://github.com/justinamiller/DotNet-Coding-Guidelines","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinamiller%2FDotNet-Coding-Guidelines","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinamiller%2FDotNet-Coding-Guidelines/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinamiller%2FDotNet-Coding-Guidelines/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justinamiller%2FDotNet-Coding-Guidelines/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justinamiller","download_url":"https://codeload.github.com/justinamiller/DotNet-Coding-Guidelines/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485290,"owners_count":20946398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dotnet","engineering-guidelines"],"created_at":"2024-10-14T11:11:30.706Z","updated_at":"2025-04-06T13:12:06.921Z","avatar_url":"https://github.com/justinamiller.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# C# Coding Guidelines \u0026 Practices\n\nThis repo highlights the list of software engineering guidelines in general. Most of these are industry-wide conventions, thus using them will ensure that your code is easily readable by people who are not you.\n\nJust keep in mind that this post isn't about how you should indent your code, but it's more of a guidlines on how to write clean code that are easy to manage. With that said, if you are leading a team or even a single contributor developer who wanted to become better, having a set of coding guidelines is a great start to make that happen.\n\nAlso, feel free to add your own tips through pull requests.\n\n### Try to avoid boxing like in the following:\n```\nint x = 32;\nobject o = x;\n```\nBoxing is the process of wrapping a value type such as a primitive or struct inside an object that lives on the heap. Unboxing is gettting the orginal value back out again.\n\n👍 Map to matching primitive or struct variable instead:\n\n```\nint x = 32;\nint y = x;\n```\n\n\n### Try to avoid the traditional if-else statements like in the following:\n\n```\nint statusCode;\nif (condition)\n{\n   statusCode = 1;\n}\nelse\n{\n   statusCode = 2;\n}\n```\n\n👍 Do use ternary conditional operator (?:) instead:\n\n```\nint statusCode = condition ? 1 : 2;\n```\n\nThe preceding code is much cleaner, easier to read and understand. On top of that, it's more concise.\n\n### Try to avoid nested Ternary operators:\n\n```\npublic string GetJobStatus(Job job)\n{\n  return job.IsRunning ? \"Running\" : job.HasErrors ? \"Failed\" : \"Succeeded\";\n}\n```\n\n👍 Use another line to express the nested operation as a separate statement for readability:\n\n```\nif (job.IsRunning)\n  {\n    return \"Running\";\n  }\nreturn job.HasErrors ? \"Failed\" : \"Succeeded\";\n```\n\nNesting ternary operators results in the kind of code that may seem clear as day when you write it, but six months later could leave maintainers (or future you) scratching their heads.\n\n### Try to avoid using if statement for null checks like in the following:\n\n```\nif (something != null)\n{\n    if (something.Other != null)\n    {\n        return something.Other.Whatever;\n    }\n}\n```\n\n👍 Do use null conditional (?.) operator instead:\n\n```\nreturn something?.Other?.Whatever;\n```\n\nThe preceding code is also much cleaner and concise.\n\n### Try to avoid complex if-else statements for null checks like in the following:\n\n```\nif (something != null)\n{\n    if (something.other != null)\n    {\n        return something.other.whatever;\n    }\n    else\n    {\n        return string.empty;\n    }\n}\nelse\n{\n    return string.empty;\n}\n```\n\n👍 Do use null coalescing (??) operator instead:\n\n```\nreturn something?.other?.whatever ?? string.empty;\n```\n\n### Try to avoid using the following code when returning a default value when an object is null:\n\n```\nint? number = null;\nvar n = number.HasValue ? number : 0;\n```\n\n👍 Do use null coalescing (??) operator as well:\n\n```\nvar n = number ?? 0;\n```\n\n👍 or alternatively, you could do:\n\n```\nvar n = number.GetValueOrDefault();\n```\n\n### Try to avoid using the equality operator (==) or HasValue for nullable variable check like in the following:\n\n```\nint? number = null;\n\nif (number == null)\n{\n    //do something\n}\n\nif (!number.HasValue)\n{\n    //do something\n}\n```\n\n👍 While the preceding code is fine, we can still improve that by using the is keyword like in the following:\n\n```\nint? number = null;\n\nif (number is null)\n{\n    //do something\n}\n```\n\n### Avoid code without braces ({}) for single conditional if statement, for and foreach loops like in the following:\n\n```\nif (condition) action;\n```\n\nWithout the braces, it is too easy to accidentally add a second line thinking it is included in the if, when it isn’t.\n\n👍 Always use braces instead:\n\n```\nif (condition) { action; }\n\n//or better\nif (condition)\n{\n    action;\n}\n```\n\n###  Try to avoid using multiple if-else statements like in the following:\n\n```\nif (condition)\n{\n   //do something\n}\nelse if (condition)\n{\n   //do something\n}\nelse if (condition)\n{\n   //do something\n}\nelse (condition)\n{\n   //do something else\n}\n```\n\n👍 Do use switch statements instead:\n\n```\nswitch (condition)\n{\n   case 1:\n      //do something\n      break;\n   case 2:\n      //do something\n      break;\n   case 3:\n      //do something\n      break;\n   default:\n      //do something else\n     break;\n}\n```\n👍 But prefer switch expressions over switch statements where possible like in the following:\n\n```\ncondition switch\n{\n    1 =\u003e //do something;\n    2 =\u003e //do something;\n    3 =\u003e //do something;\n    _ =\u003e //do something else;\n}\n```\n\nThe preceding code is more concise yet, still easy to read and understand. (Note, only available in C# 8 or later versions) 💡 Exceptions - There are cases that if-else statements would make more sense than using switch statements. One such example could be, if the condition involves different objects and complex conditions, though if the conditional logic here boils down to checking whether an object matches a certain shape in terms of property values, you might want to explore recursive pattern matching.\n\n### Do use the using statement when working with objects that eat resources or implements IDisposable interface:\n\n```\nusing (MemoryStream stream = new MemoryStream())\n{\n    // do something\n}\n```\n\n👍 Or prefer to use the new using declaration introduced in C# 8 like in the following:\n\n```\nusing var stream = new MemoryStream();\n// do something\n```\n\nThe preceding code reduces the number of curly braces in your method, but it can still be seen easily where a resource is disposed. For more information, see: \"pattern-based using\" and \"using declarations\".\n\n⚠ Do not use either of the above if the IDisposable is the return value of your method:\n\n```\nStream GetABrokenFileStream()\n{\n    // this is wrong! The stream will be disposed when you exit the method\n    using var fileStream = File.OpenRead(\"path to my file\");\n    return fileStream;\n}\n```\n\n### Avoid concatenating strings with the + sign/symbol like in the following:\n\n```\nstring space = \"Vianne\";\nstring greetings = \"Hello \" + name + \"!\";\n```\n\n👍 Use string.Format() method instead:\n\n```\nstring name = \"Vynn\";\nstring greetings = string.Format(\"Hello {0}!\", name);\n```\n\n👍 Or prefer using string interpolation ($) instead where possible:\n\n```\nstring name = \"Vjor\";\nstring greeting = $\"Hello, {name}!;\n```\n\nThe preceding code is much more concise and readable compared to other approaches.\n\n### Try to avoid string.Format() when formatting simple objects like in the following:\n\n```\nvar date = DateTime.Now;\nstring greetings = string.Format(\"Today is {0}, the time is {1:HH:mm} now.\", date.DayOfWeek, date);\n```\n\n👍 Use string interpolation instead:\n\n```\nvar date = DateTime.Now;\nstring greetings = $\"Today is {date.DayOfWeek}, the time is {date:HH:mm} now.\");\n```\n\nThe preceding code is much easier to understand and concise. However, there are certain cases that using the string.Format() would makes more sense. For example, when dealing with complex formatting and data manipulation. So, use your judgement when to apply them in situations.\n\n### Avoid using specific type for complex objects when defining variables like in the following:\n\n```\nList\u003cRepository.DataAccessLayer.Whatever\u003e listOfBlah = _repo.DataAccessLayer.GetWhatever();\n```\n\n👍 Use the var keyword instead:\n\n```\nvar listOfBlah = _repo.DataAccessLayer.GetWhatever();\n```\n\n👍 Same goes for other local variables:\n\n```\nvar students = new List\u003cStudents\u003e();\nvar memoryStream = new MemoryStream();\nvar dateUntilProgramExpiry = DateTime.Now;\n```\n\n### Try to avoid one-liner method implementation with curly braces like in the following:\n\n```\npublic string Greeter(string name)\n{\n    return $\"Hello {name}!\";\n}\n```\n\n👍 Do use Expression-bodied (=\u003e) implementation instead:\n\n```\npublic string Greeter(string name) =\u003e $\"Hello {name}!\";\n```\n\nThe preceding code is more concise while maintaining readability.\n\n### Avoid object initialization like in the following:\n\n```\nPerson person = new Person();\nperson.FirstName = \"Vianne\";\nperson.LastName = \"Durano\";\n```\n\n👍 Do use object and collection initializers instead:\n\n```\nvar person = new Person\n{\n    FirstName = \"Vianne\",\n    LastName = \"Durano\"\n};\n```\n\nThe preceding code is more natural to read and the intent is clear because the properties are defined within braces.\n\n### Avoid creating a class just to return two simple result sets like in the following:\n\n```\npublic Person GetName()\n{\n    var person = new Person\n    {\n        FirstName = \"Vincent\",\n        LastName = \"Durano\"\n    };\n\n    return person;\n}\n```\n\n👍 Do use Tuples instead where possible:\n\n```\npublic (string FirstName, string LastName) GetName()\n{\n    return (\"Vincent\", \"Durano\");\n}\n```\n\nThe preceding code is more convenient for accessing objects and manipulating the data set. Tuples replaces the need to create a new class whose sole purpose is to carry around data.\n\n### Try to create an Extention Methods to perform common tasks such as conversion, validation, formatting, parsing, transformation, you name it. So, instead of doing the following:\n\n```\nstring dateString = \"40/1001/2021\";\nvar isDateValid = DateTime.TryParse(dateString, out var date);\n```\n\nThe preceding code is perfectly fine and should handle the conversion safely. However, the code is bit lengthy just to do basic conversion. Imagine you have tons of the same code conversion cluttering within the different areas in your project. Your code could turn into a mess or potentially causes you alot of development time overtime.\n\n👍 To prevent that, you should consider creating a helper/utility functions to do common tasks that can be reused across projects. For example, the preceding code can now be converted to following extension:\n\n```\npublic static class DateExtensions\n{\n     public static DateTime ToDateTime(this string value)\n         =\u003e DateTime.TryParse(value, out var result) ? result : default;\n}\n```\n\nand you will be able to use the extension method like in the following anywhere in your code:\n\n```\nvar date = \"40/1001/2021\".ToDateTime();\n```\n\nThe preceding code makes your code concise, easy to understand and provides convenience.\n\nThe preceding code removes alot of noise in your code when injecting dependencies as you don't need to write private readonly declarations which can make your code cleaner.\n\nIn situations where you want to expose one of the fields to be public, you can define and set it in the constructor as what you would normally do. Otherwise, the arguments are marked as private fields.\n\n### Avoid using .NET predefined data types such as Int32, String, Boolean, etc.:\n\n```\nString firstName;\nInt32 orderCount;\nBoolean isCompleted;\n```\n\n👍 Do use built-in primitive data types instead:\n\n```\nstring firstName;\nint orderCount;\nbool isCompleted;\n```\n\nThe preceding code is consistent with the Microsoft’s .NET Framework and more natural to read.\n\n### Do not use initials as identifier abbreviations like in the following:\n\n```\nprivate readonly PersonManager _pm;\n```\n\nThe main reason for this is that it can cause confusion and inconsistency when you have class that might represents the same thing like in the following:\n\n```\nprivate readonly ProductManager _pm;\n```\n\n👍 Instead, do choose clarity ver brevity like in the following:\n\n```\nprivate readonly PersonManager _personManager;\nprivate readonly ProductManager _productManager;\n```\n\nThe preceding code provides more clarity as it clearly suggests what the object is about.\n\n### Do organize namespaces with a clearly defined structure. Take a look at the following example:\n\n```\nnamespace ProjectName.App.Web\nnamespace ProjectName.Services.Common\nnamespace ProjectName.Services.Api.Payment\nnamespace ProjectName.Services.Api.Ordering\nnamespace ProjectName.Services.Worker.Ordering\n```\n\nGenerally namespaces should reflect the folder hierarchy within a project. The preceding code suggest good organization of your code within the project, allowing you to navigate between layers easily.\n\n### Do use singular form, noun or noun phrases to name a class:\n\n```\npublic class Person\n{\n    //some code\n}\n\npublic class BusinessLocation\n{\n    //some code\n}\n\npublic class DocumentCollection\n{\n    //some code\n}\n```\n\nThis enables you to easily determine if an object holds a single item value or collection. Imagine, if you have a List\u003cPeople\u003e vs List\u003cPerson\u003e. It's just odd to put plural form names in a List or Collection.\n\n### Do use nouns or adjective phrases for Property names as well. When naming boolean properties or variables, you may add the prefix \"can\", \"is\", \"has\", etc. just like in the following:\n\n```\npublic bool IsActive { get; set; }\npublic bool CanDelete { get; set; }\n\n//variables\nbool hasActiveSessions = false;\nbool doesItemExist = true;\n```\n\nAdding those suffixes will provide more value to the caller.\n\n### Do use Pascal Casing for Class, Method, Property and Constant variable names:\n\n```\npublic class ClassName\n{\n    const int MaxPageSize = 100;\n\n    public string PropertyName { get; set; }\n\n    public void MethodName()\n    {\n        //do something\n    }\n}\n```\n\nThis is so that our code is consistent with the Microsoft .NET Framework.\n\n### Do use Camel Casing for method arguments and local variables:\n\n```\npublic void MethodName(CreatePersonRequestDto requestDto)\n{\n       var firstName = requestDto.FirstName;\n}\n```\n\nThis is so that our code are consistent with the Microsoft .NET Framework.\n\n### Do use meaningful and self-explanatory names for classes, methods and properties:\n\n```\nint daysUntilProgramExpiry;\n\npublic Person GetPersonProfileById(long personId)\n{\n       //do something\n}\n```\n\nThis makes your code easier to read and understand without having you to write (or atleast minimizes) comments of what the code does.\n\n### Do suffix asynchronous methods with the Async word:\n\n```\npublic async Task\u003cList\u003cPerson\u003e\u003e GetPersonProfileByIdAsync(long personId)\n{\n     //do something\n}\n```\n\nThis enable developers to easily identify synchronous vs asynchronous methods by just looking at the method name itself.\n\n### Do prefix interfaces with the capital letter I\n\n```\npublic interface IPersonManager\n{\n   //...\n}\n```\n\nThis is to easily distinguish between an interface and classes. In fact, it's a well known standard for defining interfaces.\n\n### Do prefix global variables and class fields with underscores (\\_):\n\n```\nprivate readonly ILogger\u003cClassName\u003e _logger;\nprivate long _rowsAffected;\nprivate IEnumerable\u003cPersons\u003e _people;\n```\n\nThis is to easily differentiate between local and global identifiers/variables.\n\n### Do declare all member variables and fields at the top of a class, with static fields at the very top:\n\n```\nprivate static string _externalIdType;\nprivate readonly ILogger\u003cPersonManager\u003e _logger;\nprivate int _age;\n```\n\nThis is just a generally accepted practice that prevents the need to hunt for variable declarations.\n\n### Do consider putting all your private methods at the bottom after public methods:\n\n```\npublic class SomeClass\n{\n    public void SomePublicMethodA()\n    {\n\n    }\n\n    // rest of your public methods here\n\n    private void SomePrivateMethodA()\n    {\n\n    }\n\n    private void SomePrivateMethodB()\n    {\n\n    }\n}\n```\n\n### Try to avoid grouping your code into regions like in the following:\n\n```\n#region Private Members\n    private void SomePrivateMethodA()\n    {\n\n    }\n\n    private void SomePrivateMethodB()\n    {\n\n    }\n\n#endregion\n```\n\nThe preceding code is a code smell which could potentially make your code grow without you realizing it. I admit that I have used this feature many times to collapse the code within a class. However, I realize that hiding code into regions won't give you any value aside from maximizing your visual view when the region is collapsed. If you are working with a team of developers on a project, chances are, other developers will append their code in there until the code get's bigger and bigger over time. As a good practice, it's always recommended to keep your classes small as possible.\n\nIf you have tons of private methods within a class, you could split them into a separate class instead.\n\n### Try to use short-hand names only when they’re generally known:\n\n```\nprivate readonly CreateQuestionDefinitionRequestDto _requestDto;\n```\n\nIt would be too much to name a variable \"createQuestionDefinitionRequestDto\" when you know that the variable/parameter is a request object. The same thing applies for FTP, UI, IO, etc. It's perfectly fine to use abbreviation for as long as they're generally known, otherwise it would be counter productive not to do so.\n\n### Avoid underscores (\\_) in between identifier names:\n\n```\npublic PersonManager person_Manager;\nprivate long rows_Affected;\nprivate DateTime row_updated_date_time;\n```\n\nThe reason being is that C# isn't postgres. Seriously, it's to be consistent with the Microsost .NET Framework convention and makes your code more natural to read. It can also avoid \"underline stress\" or inability to see underline.\n\n### Do not use SCREAMING CAPS for constants or read-only variables:\n\n```\npublic static const string EXTERNALIDTYPE = \"ABC\";\npublic static const string ENVIRONMENT_VARIABLE_NAME = \"TEST\";\n```\n\nThey just grab too much attention.\n\n### Do not use Hungarian notation or any other type identification in identifiers (except interfaces):\n\n```\nint iCounter;\nstring strName;\nstring spCreateUsers;\nOrderingService svcOrdering;\n```\n\nVisual Studio code editor already provides helpful tooltips to determine object types. In general, you want to avoid type indicators in the identifier.\n\n### Do not use an \"Enum\" suffix in enum type names and do not use plural form names for enums.\n\nThe following is an example for defining an enum:\n\n```\npublic enum BeerType\n{\n  Lager,\n  Ale,\n  Ipa,\n  Porter,\n  Pilsner\n}\n```\n\nAgain, this is to be consistent with the Microsoft .NET framework and avoids type indicators in the identifier.\n\n### Try to use record types for immutable objects. Record types is a new feature introduced in C# 9 where it simplfies your code. For example, the following code:\n\n```\npublic class Person\n{\n    public string FirstName { get; init; }\n    public string LastName { get; init; }\n\n    public Person(string firstName, string lastName)\n    {\n        FirstName = firstName;\n        LastName = lastName;\n    }\n}\n```\n\ncan be written in the following way using record:\n\n```\npublic record Person(string FirstName, string LastName);\n```\n\nUsing record types will automatically generates the boilerplate code for you and keeping your code concise. Records will be really useful for defining DTOs, Commands or any object that carries immutable data around. For more information about this feature, see: [Record Types](https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/)\n\n### Use Attributes on local functions\nbefore c# 9.0 we used C# compiler directive on local functions\n\n```\nstatic void Main(string[] args)\n        {\n            static void DoAction()\n            {\n                // DoAction\n\n                Console.WriteLine(\"DoAction...\");\n            }\n\n#if DEBUG\n            DoAction();\n#endif\n        }\n```\nin c# 9.0 can be written in the following way using Attributes on local functions:\n\n```\nstatic void Main(string[] args)\n        {\n            [Conditional(\"DEBUG\")]\n            static void DoAction()\n            {\n                // Do Action Here\n\n                Console.WriteLine(\"Do Action...\");\n            }\n\n            DoAction();\n        }\n```\n\n### Arrange your code before commits\n```\nVisual Studio shortcut : CRTL+K+D\n```\n\n### Use local function for conditions\n```\nif (RequestIsValid(request.Id))\n{\n\n}\n\nbool RequestIsValid(int id)\n{\n    return id \u003e 0;\n}\n```\n\n### Always remove unnecessary usings and sort them\n```\nVisual Studio shortcut : CRTL+R+G\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustinamiller%2Fdotnet-coding-guidelines","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustinamiller%2Fdotnet-coding-guidelines","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustinamiller%2Fdotnet-coding-guidelines/lists"}