Framework Guidelines
Use C# type aliases instead of the types from the System
namespace (AV2201) 
For instance, use object
instead of Object
, string
instead of String
, and int
instead of Int32
. These aliases have been introduced to make the primitive types first class citizens of the C# language, so use them accordingly.
Exception: When referring to static members of those types, it is custom to use the full CLS name, e.g. Int32.Parse()
instead of int.Parse()
. The same applies to members that need to specify the type they return, e.g. ReadInt32
, GetUInt16
.
Prefer language syntax over explicit calls to underlying implementations (AV2202) 
Language syntax makes code more concise. The abstractions make later refactorings easier (and sometimes allow for extra optimizations).
Prefer:
(string, int) tuple = ("", 1);
rather than:
ValueTuple<string, int> tuple = new ValueTuple<string, int>("", 1);
Prefer:
DateTime? startDate;
rather than:
Nullable<DateTime> startDate;
Prefer:
if (startDate != null) ...
rather than:
if (startDate.HasValue) ...
Prefer:
if (startDate > DateTime.Now) ...
rather than:
if (startDate.HasValue && startDate.Value > DateTime.Now) ...
Prefer:
(DateTime startTime, TimeSpan duration) tuple1 = GetTimeRange();
(DateTime startTime, TimeSpan duration) tuple2 = GetTimeRange();
if (tuple1 == tuple2) ...
rather than:
if (tuple1.startTime == tuple2.startTime && tuple1.duration == tuple2.duration) ...
Don’t hard-code strings that change based on the deployment (AV2207) 
Examples include connection strings, server addresses, etc. Use Resources
, the ConnectionStrings
property of the ConfigurationManager
class, or the Settings
class generated by Visual Studio. Maintain the actual values into the app.config
or web.config
(and most definitely not in a custom configuration store).
Build with the highest warning level (AV2210) 
Configure the development environment to use Warning Level 4 for the C# compiler, and enable the option Treat warnings as errors . This allows the compiler to enforce the highest possible code quality.
Avoid LINQ query syntax for simple expressions (AV2220) 
Rather than:
var query = from item in items where item.Length > 0 select item;
prefer the use of extension methods from the System.Linq
namespace:
var query = items.Where(item => item.Length > 0);
Since LINQ queries should be written out over multiple lines for readability, the second example is a bit more compact.
Use lambda expressions instead of anonymous methods (AV2221) 
Lambda expressions provide a more elegant alternative for anonymous methods. So instead of:
Customer customer = Array.Find(customers, delegate(Customer customer)
{
return customer.Name == "Tom";
});
use a lambda expression:
Customer customer = Array.Find(customers, customer => customer.Name == "Tom");
Or even better:
var customer = customers.FirstOrDefault(customer => customer.Name == "Tom");
Only use the dynamic
keyword when talking to a dynamic object (AV2230) 
The dynamic
keyword has been introduced for working with dynamic languages. Using it introduces a serious performance bottleneck because the compiler has to generate some complex Reflection code.
Use it only for calling methods or members of a dynamically created instance class (using the Activator
) as an alternative to Type.GetProperty()
and Type.GetMethod()
, or for working with COM Interop types.
Favor async
/await
over Task
continuations (AV2235) 
Using the new C# 5.0 keywords results in code that can still be read sequentially and also improves maintainability a lot, even if you need to chain multiple asynchronous operations. For example, rather than defining your method like this:
public Task<Data> GetDataAsync()
{
return MyWebService.FetchDataAsync()
.ContinueWith(t => new Data(t.Result));
}
define it like this:
public async Task<Data> GetDataAsync()
{
string result = await MyWebService.FetchDataAsync();
return new Data(result);
}
Tip: Even if you need to target .NET Framework 4.0 you can use the async
and await
keywords. Simply install the Async Targeting Pack.