.NET Compiler Platform, better known as Roslyn, has been one of the best things that happened to C#. In short, it is a compiler made with IDE integration and extensibility in mind. It provides us with hooks to add our own analysis and transformations to the process of compilation. Why is that important? If there was ever a coding rule specific to just one of your projects, that you had to inforce with lots of discipline and diligence, but would rather rely on the compiler for it, or a routine operation you could easily automate if only you could write an IDE extension – Roslyn will make this a reality. It allows you to write code, C# code in my case, that will run as a Visual Studio extension, analyze the code other devs are working on and help them modify it.
Unfortunately, despite initially releasing with Visual Studio 2015, there is still lack of tutorials teaching how to do things beyond ‘Hello world’. For serious development, the best way to learn is to read official documentation wiki and study other prjects available on github - quite a lot of overhead, even if Roslyn is worth it. This series will provide with a more streamlined roadmap - enough knowledge to do useful things and guidelines for farther research. Through the series we will build a refactoring extension for Visual Studio and a simplistic analyzer dll to include into a project. Both small enough to comprehend in an hour, yet performing useful work, solving a task the likes of which you may expect to want to automate yourself in your project. As well as techncial infromation, which can be quite overwhelming at first site, I will try to give hints on the general flow of Rolsyn development: how to decide where to start, how to deal with roadblocks, how to concentrate on important things first.
This article sums up my experience conducting 100+ technical interviews for a big software development outsourcer\outstuffer. It is aimed at interviewers with the goal of helping them prepare for the process and handle typical issues that come up as well as responsibility to both their company and the person being interviewed.
In part 1 we learned that you can swap parts of an Expression Tree to another compatible (i.e. with a matching return type) expression. Swapping is, in fact, the easiest thing to do - with a bit more work we can construct a serializable representation of almost any bit of C# code. This opens great avenues for Domain Driven Development and introducing hot-swappable, dynamic, yet safe parts of logic to your application.
One of the best examples of the power we get is shown by introducing a reusable expression function with LINQKit.
internal static class AddressSubqueries
{
internal static Expression<Func<string, string, string>> FormatCityAndProvince =
(city, province) => "The glorious city of " + city
+ " of the wonderful province of " + province;
}
//used like this:
public IQueryable<string> GetStandardAddressDescription(int addressId)
{
return DataContext
.Addresses.AsExpandable() // this hooks in LINQKit
.Where(x => x.AddressId == addressId)
.Join(
DataContext.StateProvinces,
adr => adr.StateProvinceId,
prov => prov.StateProvinceId,
(adr, prov) => AddressSubqueries.
FormatCityAndProvince // <==
.Invoke(adr.City, prov.Name))
.FirstOrDefault();
}
In the previous part we have determined that:
- IQueryably consists of a Provider and an Expression Tree
- Expression Trees can be combined almost as easily as pieces of C# code
In this article, we will look at treating our queries are reusable chunks of logic and combining them into more complex yet still readable queries like this:
public IQueryable<ProductModelOrderStatisticsDto> GetProductModelOrderStats()
{
// a bigger, more detailed query
IQueryable<WorkOrderSummaryDto> allDurationsAndRoutings =
GetWorkOrderSummaries();
// is wrapped by an aggregation to retrieve statistics
var averagePerModel = allDurationsAndRoutings
.GroupBy(x => new { x.ProductModelId, x.ModelName })
.Select(x => new ProductModelOrderStatisticsDto
{
ModelId = x.Key.ProductModelId,
ModelName = x.Key.ModelName,
AverageDuration = x.Where(y => y.DurationDays.HasValue)
.Average(y => y.DurationDays.Value),
AverageRoutings = x.Average(y => y.RoutingsCount)
});
return averagePerModel;
}
Many .NET developers don’t realize or don’t pay attention to the differences between IEnumerable and IQueryable. Most tutorials on the topic don’t go beyond trivial examples, thus missing the huge potential hidden inside.
IQueryable is IEnumerable and much more.