forked from MyUNiDAYS/StyleGuide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
StyleGuide.cs
231 lines (198 loc) · 5.95 KB
/
StyleGuide.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
// Usings at the top, outside the namespace
using System;
// Namespace next
// Braces on new lines
namespace UD.Core
{
// Tabs over spaces
/// <summary>
/// Classes
/// sealed by default
/// internal (no explicit modifier) by default
/// Braces on new lines
/// No line wrapping for : extends/implements
/// Ordering of contents:
/// private members
/// public members
/// constructors
/// public and private methods, placed in a logical order
/// Interface implementations to be in the same order as on the interface
///
/// Attributes
/// Prefer one per line, rather than comma separated
/// </summary>
[Attribute]
[Attribute]
sealed class StyleGuide : IDisposable
{
/// <summary>
/// Private fields
/// Lower case first letter
/// Camel Casing
/// No explicit private modifier
/// Placed at top of class
/// </summary>
string anExamplePrivateField;
/// <summary>
/// Public fields
/// Upper case first letter
/// Camel Casing
/// Placed at top of class, after private members
/// </summary>
public string AnExamplePublicField;
/// <summary>
/// Public Property
/// Upper case first letter
/// Camel Casing
/// Place at top of class, after private members
/// </summary>
public string PublicProperty { get; set; }
/// <summary>
/// Getter only property
/// Prefer lambdas over { get { return "example"; } } where sensible
/// </summary>
string getter => "example;";
/// <summary>
/// Constructors
/// Next in class after public members
/// </summary>
public void StyleGuide()
{
}
/// <summary>
/// Private method
/// Upper case first letter
/// Camel Casing
/// No explicit private modifier
/// Braces on new lines
/// Below constructors within class
/// </summary>
void PrivateMethod()
{
}
void GeneralSyntax()
{
// explicit this. for member access
this.anExamplePrivateField = "new value";
// explicit this. for member calls
this.PrivateMethod();
// No braces for single line IFs (same for all blocks)
if (this.anExamplePrivateField == "some value")
this.anExamplePrivateField = "some other value";
// No braces for single line LOCKS (same for all blocks)
lock (this.anExamplePrivateField)
this.anExamplePrivateField = "some other value";
// No braces on outer Using when multiple present, no indentation on inner
using (this)
using (this)
{
// do something
}
// Use braces for the THEN/ELSE block of an IF when it only has one line, when the other block is multiline (and has braces)
if (this.anExamplePrivateField == "some value")
{
this.anExamplePrivateField = "some other value";
}
else
{
this.anExamplePrivateField = "some different value";
this.AnExamplePublicField = "a new value";
}
// Local variables
// Prefer var over explicit types
// Variabes should have semantic names
// Lower case first letter
// Camel Case
var ageInYears = 21;
// DateTimes
// Named as <event>On, eg. bornOn, startedOn, endsOn
// Always specify as UTC when new()ing a DateTime
var bornOn = new DateTime(2017, 10, 23, 12, 32, 45, DateTimeKind.UTC);
var listOfWords = new[] { "one", "two", "three" };
// Keep "LINQ" lambdas legible with clear formatting
listOfWords
.Where(item => item.Length <= 3)
.Select(item => item[0])
.OrderBy(item => item)
.ToArray();
}
/// <summary>
/// Methods that contain logic
/// </summary>
int CyclomaticComplexity()
{
// Keep nesting to a minimum, avoid redundant elses
if (this.anExamplePrivateField == null)
return 0;
if (this.AnExamplePublicField == null)
return 0;
// Keep logic inside IFs simple.
// If it is complex or involves multiple operands, consider using local variables
if (this.anExamplePrivateField == "winner" && this.AnExamplePublicField = "Chicken Dinner")
return 10;
}
/// <summary>
/// Methods with return values
/// Prefer semantic abstract data types to wrap multiple return values, over OUT or REF arguments
/// Obey CQS, don't cause side effects and return a value where possible (except operation results)
/// </summary>
SomeAbstractType PerformGetOperation()
{
// prefer object initializers
// no redundant () for default constructor use
return new SomeAbstractType
{
ReturnValue1 = "value 1",
ReturnValue2 = 2
};
}
/// <summary>
/// Static methods
/// Make methods static where possible
/// </summary>
static void DoAThing()
{
// no references in here to `this.`
}
/// <summary>
/// No #Regions around Interface Implementations, or at all
/// </summary>
public void Dispose()
{
throw new NotImplementedException();
}
/// <summary>
/// Private classes
/// Encapsulate private classes that are only used for internal (to the parent class) data, rather than putting them outside the class, available for other uses
/// Place them at the bottom of the file
/// </summary>
sealed class SomeAbstractType
{
public string ReturnValue1 { get; set; }
public int ReturnValue2 { get; set; }
}
}
/// <summary>
/// Enums
/// </summary>
enum MyOptions
{
// Prefer to specify the first value as explicitly non-zero, so you can tell the difference
// from default(MyOptions), unless it truly makes sense to have a default / "null" value
OptionA = 1,
OptionB = 2,
OptionC = 3
}
// Specify [Flags] when you're intending to use the enum as a flag set
[Flags]
enum FlagOptions
{
// powers of two for the canonical values
OptionA = 1,
OptionB = 2,
OptionC = 4,
// specify combinations only if they have semantic value on their own
// don't calculate their value manually
StandardOptions = OptionB | OptionC
}
}