- Project >
Properties
>Build
>Treat warnings as errors
>All
- Set
Output type
toWindows Application
if you don't need Console. - Suppress Code Analysis warnings by using the
SuppressMessage
attribute and don't useGlobalSuppressions.cs
because it refers to warned methods by string and cannot keep track of the methods after they are renamed.
[SuppressMessage("Microsoft.Usage", "CA2202")]
- Don't use ILMerge does not support the latest .NET Framework.
- Framework Design Guidelines
- C# Coding Conventions
- Best Practices for Using Strings in .NET
- Managed Threading Best Practices
- Microsoft REST API Guidelines
- Best practices for exceptions
- Error Message Guidelines
- Mark a class
static
by default. If a class has to not to bestatic
,seal
it. - Use
int.Parse
if a parsed object is string becauseint.Parse
is faster thanConvert.ToInt32
. - Use
Array.BinarySearch(...)
orList.BinarySearch(...)
if the array or the list is sorted. - Specify an initial size in the constructor of a collection if the size is known.
throw new InvalidEnumArgumentException(nameof(x), (int)x, typeof(Enum1))
in the default section ofswitch
statement if an input is enum.throw new ArgumentOutOfRangeException(nameof(x), x, "Must be foo or bar.")
in the default section ofswitch
statement if an input is not enum.- Don't write parentheses of
catch
if you don't need the information of the thrown exception. - A rather than B
- Use
<
and<=
for readability rather than>
and>=
. - Use fields rather than auto-implemented properties for simplicity.
- Use
ToList()
rather thanToArray()
unless the size is pre-fixed. - Use
string.Concat(ss)
rather thanstring.Join("", ss)
. - The following tells when to use
'+'
,string.Concat(...)
, or string interpolation without formatting.- If two strings are concatenated, use
'+'
. For example,{var} + {var2}
. - If more than two strings are concatenated using one or zero string literal, use
string.Concat(...)
. For example,string.Concat(var1, var2, var3)
orstring.Concat(var1, "foo", var2)
. - Otherwise, use string interpolation. For example,
$"foo{var1}bar{var2}"
.
- If two strings are concatenated, use
- Use
ValueTuple
rather thanTuple
. - Use
ValueTuple.Create(...)
rather thannew ValueType(...)
. - Use
xs.GetRange(skipCount, takeCount)
rather thanxs.Skip(skipCount).Take(takeCount)
- Use
struct
rather thanstatic class
as a key ofDictionary
becausestatic class
is a reference type and you will accidentally compare addresses of the heap.
- Use
- Use log4net rather than EventSource and TraceSource though they are more modern approaches because EventSource is not handy and TraceSource cannot format timestamp and cannot roll log files.
- Don't commit your code, which points to the production database, to a shared repository.
- [Health check] If a newcomer builds and runs your source code right out of the box from a shared repository, will it cause him to access a production database or publish the app to a production site? If so, fix it.
- Be minimalistic for your next maintainers' sake
- Avoid unnecessary configurations.
- Avoid unnecessary decorations.
- Avoid overly minor third-party libraries because they go out of fashion quickly.
- Make production environment special and non-production environment general.
Recommended
/* pseudo code */
GetEnvironment()
{
if(specific-condition)
{
return production;
}
else
{
return non-production;
}
}
Not recommended
/* pseudo code */
GetEnvironment()
{
if(specific-condition)
{
return non-production;
}
else
{
// For example, if defining the word "DEV" somewhere is the condition to lead to a non-production environment, defining "DEVELOPMENT" or "UAT" or not defining any word leads to the production environment.
return production;
}
}
Environment.CurrentDirectory
Environment.MachineName
Environment.NewLine
Environment.OSVersion
Environment.UserDomainName
Environment.UserName
Environment.Version // Unreliable
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
- Assembly Versioning
- Use "yyyy.m.d.*" as AssemblyVersion to automatically increment the revision number
- yyyy.m.d is a release date, which needs to be manually maintained
- By Omitting AssemblyFileVersion, AssemblyFileVersion implicitly mirrors AssemblyVersion
- Debug.Print (string message)
- Debug.Assert (bool condition, string message)
- Debug.WriteLine (string message, string category)
- Debug.WriteLineIf (bool condition, string message, string category)
Debug.WriteLine(var1, System.Reflection.MethodBase.GetCurrentMethod().Name);
Debug.WriteLine(var1, nameof(var1));
When an exception occurs, .pdb
shows a stack trace that tells which method of which class on which line of which file failed. However, some of the info is lost if optimized.
Shows stack trace when exception occurs | Can attach debugger | Impact on performance | |
---|---|---|---|
full |
True | True | True |
pdbonly |
True | False | False |
- Install
Microsoft Child Process Debugging Power Tool
- Start Visual Studio 2017 > Menu bar >
Debug
>Other Debug Targets
>Child Process Debugging Settings
>Enable child process debugging
> Check - Open the solution of a child project in Visual Studio
- Open
Properties
of the child project >Build
>Advanced
>Full
orPdb-only
- Open
Properties
of the child project >Build
>Optimize code
> Uncheck - Build the child project to create the child .exe
- Open
- Open the solution of a parent project in Visual Studio
- Open
Properties
of the parent project >Debug
>Enable native code debugging
> Check - Write in the parent project to call the child .exe
- Open a source file of the child .exe within the same Visual Studio and set a breakpoint in it
- Run the parent project
- Open
SortedDictionary | SortedList | |
---|---|---|
This[index] | n/a | O(1) |
This[key] | O(log n) | O(log n) |
Add(key, value) | O(log n) | O(n) |
Remove(key) | O(log n) | O(n) |
ContainsKey(key) | O(log n) | O(n) |
ContainsValue(value) | O(n) | O(n) |
Memory | More | Less |