11 KiB
Coding Guide
This document serves as the official code standards guide for BurnOutSharp internal development. Please note that this is a work in progress and may not encapsulate all standards expected of new or existing code.
General Code Guidelines
This section contains information on code standards regardless of which part of the project you are working in.
Style and Naming
-
Prefer
Systemnamespaces for supporting operations before external ones. -
Ordering of
usingstatements goes:using System.*using <Alphabetical>using static <Alphabetical>using X <Alphabetical> = Y
-
Use 4 spaces for
tab. -
Curly braces should generally start on the line after but inline with the start of the previous statement, even if multiline.
if (flag) { DoSomething(); } else if (flag2 && flag3) { DoSomething2(); } -
Multi-line statements need to have following lines indented by one step at minimum.
if (flag) { DoSomething(); } else if (flag2 && flag3 && (flag4 || flag5)) { DoSomething2(); } -
Methods and classes should use
PascalCasefor naming, eveninternalandprivateones. -
Class properties should use
PascalCasefor naming, evenprotectedandinternalones. -
Instance variables should use
camelCasewith a_prefix for naming, evenprotected,internal, andprivateones. -
In-method variables should use
camelCasewithout a_prefix for naming. -
Include explicit access modifiers for all class-level properties, variables, and methods.
-
Avoid making everything
public; only include the necessary level of access. -
Avoid making every method and class instance-based. Use
staticif your method does not need to access instance variables. Usestaticif your class only contains extensions or methods used by other classes. -
Null-coalescing and null-checking operators can be used to make more readable statements and better get across what a statement or string of statements is doing.
if (obj?.Parameter != null) { ... } bool value = DoSomething() ?? false; -
#regiontags, including nested ones, can be used to both segment methods within a class and statements within a method. Indentation follows the surrounding code.#region This is the first region public static void Method() { #region This is an in-code region DoSomething(); #endregion DoSomething2(); } #endregion -
Try to avoid use of other preprocessor directives unless consulting ahead of time with the maintainers.
-
Interfaces should be listed in alphabetical order
public class Example : IBindable, IComparable, IEquatable -
Use the
<inheritdoc/>tag when possible to avoid out-of-date information.public interface IInterface { /// <summary> /// Summary to inherit /// </summary> void DoSomething(); } public class Example : IInterface { /// <inheritdoc/> public void DoSomething() { ... } }
Methods
-
Try to avoid including too much duplicate code across methods and classes. If you have duplicate code that spans more than ~5 lines, consider writing a helper method.
-
Try to use expressive naming. e.g. use names like
PrintSectionTitlesand notDoTheThing. -
Try to avoid having too many parameters in a method signature. More parameters means more things interacting.
-
Use method overloading to avoid unnecessary complexity in a single method.
Instead of: Print(string idString, byte[] idArray, int idInt) { ... } You should: Print(string id) { ... } Print(byte[] id) { ... } Print(int id) { ... } -
Use optional parameters when the default value is the most common.
Print(string id, bool toLower = false) { ... }
if-else and switch statement syntax
-
If all statements in the block are single-line, do not include curly braces.
if (flag) DoSomething(); else if (flag2) DoSomething2(); else DoSomethingElse(); -
If any of the statements is multi-line or the
if-elsestatement is multi-line, include curly braces.if (flag) { DoSomething(); } else if (flag2 && flag3 && flag4) { DoSomething2(); } else { DoSomethingElse(); DoSomethingEvenMore(); } -
If comparing against values, try to use a
switchstatement instead.As an if-else statement: if (value == 1) DoValue1(); else if (value == 2) DoValue2(); else if (value == 3) DoValue3(); else DoValueDefault(); As a switch statement: switch (value) { case 1: DoValue1(); break; case 2: DoValue2(); break; case 3: DoValue3(); break; default: DoValueDefault(); break; } -
When using a
switchstatement, if all switch cases are single-expression, they can be written in-line. You can also add newlines between cases for segmentation or clarity.If the expressions are too complex, they should not be.switch (value) { case 1: DoValue1(); break; case 2: DoValue2(); break; case 3: DoValue3(); break; default: DoValueDefault(); break; } -
If any of the switch cases are multi-expression, write all on separate lines. You can also add newlines between cases for segmentation or clarity.
switch (value) { case 1: DoValue1(); break; case 2: DoValue2(); break; case 3: DoValue3(); break; default: DoValueDefault(); DoValueAsWell(); break; }
Commenting
-
All classes and methods should contain a
summaryblock at bare minimum to explain the purpose. For methods, it is highly recommended to also includeparamtags for each parameter and areturntag if the method returns a value. Do not hesitate to useremarksas well to include additional information./// <summary> /// This class is an example /// </summary> /// <remarks> /// This class does nothing but it is useful to demonstrate /// coding standards. /// </remarks> public class Example { /// <summmary> /// This property is the name of the thing /// </summary> public string Name { get; private set; } /// <summary> /// This method is an example method /// </summary> /// <param name="shouldPrint">Indicates if the value should be printed</param> /// <returns>A value between 1 and 10, or null on error</returns> public static int? PrintAndReturn(bool shouldPrint) { ... } } -
In-code comments should use the
//syntax and not the/* */syntax, even for multiple lines.// This code block does something important var x = SetXFromInputs(y, z); // This code block does something really, // really, really, really important and // I need multiple lines to say so var w = SetWFromInputs(x, y, z); -
Comments should be expressive and fully explain what is being described. Try to avoid using slang, "pointed comments" such as "you should" or "we do".
-
If comments include links, they can either be included as-is or using the
<see href="value"/>tag// This information can be found from the following site: // <see href="www.regex101.com"/> -
Try to avoid using multiple, distinct comment blocks next to each other.
// We want to try to avoid this situation where // we have multiple things to say. // Here, the statements are not inherently linked // but still need to go in the same area. // // But here the statements are logically linked but // needed additional formatting
Project and Class Organization
This section contains information on project and class organization principles that depend on the part of the project you are working in. See the following table for details.
| Project | Description |
|---|---|
BurnOutSharp |
One file per class. See below for details on subdirectories. |
BurnOutSharp/External |
One directory per external project. |
BurnOutSharp/FileType |
One file per file type. |
BurnOutSharp/Interfaces |
One file per interface. |
BurnOutSharp/PackerType |
At least one file per packer type. Partial classes allowed. |
BurnOutSharp/ProtectionType |
At least one file per protection type. Partial classes allowed. |
BurnOutSharp/Tools |
Two files - one for extension methods and one for utilities. |
BurnOutSharp.Builder |
One file per executable type. |
BurnOutSharp.Matching |
Flat directory structure. Include interfaces and base classes. |
BurnOutSharp.Models |
One directory per executable type. One file per object model. |
BurnOutSharp.Wrappers |
One file per executable type. Common functionality goes in WrapperBase.cs. |
Test |
All functionality lives in Program.cs. |
If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document.
Code Organization
This section contains information on in-code organization principles that depend on the part of the project you are working in. See the following table for details.
| Project | Description |
|---|---|
BurnOutSharp |
Varies from file to file. |
BurnOutSharp/FileType |
Scan(Scanner, string), Scan(Scanner, Stream, string), helper methods. |
BurnOutSharp/Interfaces |
Methods ordered alphabetically. |
BurnOutSharp/PackerType |
IContentCheck implementations, INewExecutableCheck implementations, IPortableExecutableCheck implementations, IPathCheck implementations, IScannable implementations, helper methods. |
BurnOutSharp/ProtectionType |
IContentCheck implementations, INewExecutableCheck implementations, IPortableExecutableCheck implementations, IPathCheck implementations, IScannable implementations, helper methods.. |
BurnOutSharp/Tools |
Methods grouped by function. Regions ordered alphabetically. |
BurnOutSharp.Builder |
Two copies of each non-generic method: one for byte arrays and one for Streams. |
BurnOutSharp.Matching |
Varies from file to file.. |
BurnOutSharp.Models |
No methods at all, just properties. |
BurnOutSharp.Wrappers |
Follow region and method grouping from existing wrappers. |
Test |
New functionality should be added as a combination of a flag with a long and a short form, a new line in the help text, and a new method (if necessary). |
If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document.