Framework Guidelines
PFT2201: Use C# type aliases instead of the types from the System
namespace
severity: 1
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
.
PFT2202: Prefer language syntax over explicit calls to underlying implementations
severity: 1
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) ...
PFT2207: Don't hard-code strings that change based on the deployment
severity: 3
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).
PFT2210: Build with the highest warning level
severity: 1
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.
PFT2220: Avoid LINQ query syntax for simple expressions
severity: 3
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);
The second example is a bit less convoluted.
PFT2221: Use lambda expressions instead of anonymous methods
severity: 2
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");
PFT2230: Only use the dynamic
keyword when talking to a dynamic object
severity: 1
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.
PFT2235: Favor async
/await
over Task
continuations
severity: 1
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.