Framework Guidelines
Use C# type aliases instead of the types from the System
namespace
(HTA2201)
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. When referring to static members of those types, use int.Parse()
instead of Int32.Parse()
.
Exception: For interop with other languages, it is custom to use the CLS-compliant name in type and member signatures, e.g. HexToInt32Converter
, GetUInt16
.
Prefer language syntax over explicit calls to underlying implementations (HTA2202)
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 (HTA2207)
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 (HTA2210)
Configure the development environment to use the highest available warning level 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 (HTA2220)
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.
Note: This is an explicit exception of HTA2202.
Use lambda expressions instead of anonymous methods (HTA2221)
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
(HTA2230)
The dynamic
keyword has been introduced for interop with languages where properties and methods can appear and disappear at runtime. Using it can introduce a serious performance bottleneck, because various compile-time checks (such as overload resolution) need to happen at runtime, again and again on each invocation. You’ll get better performance using cached reflection lookups, Activator.CreateInstance()
or pre-compiled expressions (see here for examples and benchmark results).
While using dynamic
may improve code readability, try to avoid it in library code (especially in hot code paths). However, keep things in perspective: we’re talking microseconds here, so perhaps you’ll gain more by optimizing your SQL statements first.
Favor async
/await
over Task
continuations
(HTA2235)
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.