C#: a dynamic string interpolation

Since C# 6, the string interpolation is with us, allowing for a more readable and understandable way of concatenating, formatting and manipulating strings. The older string.Format method (aka Composite formatting) relies on the exact position of the value in a string being formatted, so it is less intuitive and less comprehensible for a reader.

Compare:
var topicName = "formatting";

var compositeFormattingOutput = string.Format("You are reading an article on {0}", topicName);

var interpolationOutput = $"You are reading an article on {topicName}";

The {topicName} is referred to as interpolatedExpression, a placeholder or just as an Expression in the following text.

The readability of the code is paid for by performance as the string interpolation is slightly slower than the string.Format method. For more details on this topic, see this article.

Issue


Imagine a case when the interpolated template (string)  is just a string, stored in a resource file or in a database, and the values for the interpolation are not available during the code compilation.
At run-time, we would like to combine the template with an object to get a formatted output  - providing the object has properties named exactly like interpolatedExpressions in the template, e.g.:




How to achieve that?

Template conversion

First, the template with interpolatedExpression (Topic)  must be converted to a composite format, so from this:
You are reading an article on {Topic}

we have to get this:
You are reading an article on {0}

As you can notice, the {Topic} has been transformed to {0}.

At the same time, we have to keep a map between the position and the original name, e.g.
0 -> Topic

To achieve that, let's define an interface for this operation:

public interface IGetCompositeFormatStringDescriptionAction
{
    ICompositeFormatStringDescription Execute(string interpolatedFormatValue);
}

The Execute method takes the template ("You are reading an article on {Topic}" and returns the instance implementing ICompositeFormatStringDescription interface:

public interface ICompositeFormatStringDescription
{
    string CompositeFormatString { get; }

    IList<string> OrderedPlaceholderNames { get; }
}

where:
  •  the CompositeFormatString property contains the converted template ("You are reading an article on {0}" 
  •  the OrderedPlaceholderNames property contains a list of interpolatedExpressions from the original string in the order they occur in it (in this case { "Topic" } )

Input item conversion

The instance/object used during the formatting as a source of values for the template's expressions must be converted too. We need to get a list of all the property's names and values and convert this list to a Dictionary. The name of the property is used as a key, the value of the property as a value, e.g.

["Topic" :"string formatting options]

The interface is defined as follows:

public interface IInstanceToDictionaryConverter
{
    Dictionary Convert(TInstance instance);
}

Putting it all together

To format a template and get the output value, let's define the following interface:
public interface IInterpolatedStringFormatter

{
    string Format<TInstance>(string format, TInstance instance);

}

In the class implementing this interface, as the template is a composite format string and the instance should have the properties needed for the template, the well-known string.Format method is used to get the output.

Example

Note: the implementation of all the above-mentioned interfaces can be found on Github - see the link at the bottom of the article.

As you can see from the following code excerpt, the same string template ("Hello {Name}") can be used with instances of different classes. These classes, besides property's names, have nothing in common (no inheritance, no common interfaces).


var person = new Person { Name = "Martin" };
var net = new Thing { Name = "Internet", Owner = person };
var something = new Something { Name = "Doe" };

Console.WriteLine(formatter.Format("Hello {Name}", person));
Console.WriteLine(formatter.Format("Hello {Name}", something));
Console.WriteLine(formatter.Format("Hello {Name}", net));
Console.WriteLine(formatter.Format("Hello {Name}, owned by {Owner.Name}", net));

internal class Person
{
   public string Name { get; set; }
}

internal class Thing
{
   public string Name { get; set; }

   public Person Owner { get; set; }
}

internal class Something
{
   public T Name { get; set; }
}

Conclusion

This approach can be used when we would like to keep the template strings to be easily readable and not tightly coupled with a  particular class or an interface. 

The actual implementation of all the described interfaces together with a runnable example is available on GitHub


Links - other sources

It is possible to find some other sources on the same topic, for example: https://haacked.com/archive/2009/01/04/fun-with-named-formats-string-parsing-and-edge-cases.aspx/

Visual Studio: work comfortably on 14" screen

Nowadays, 14" inches screens are pretty common in the ultrabook category. They offer more space than their 13" - 13.4" siblings while keeping the overall size within reasonable limits. And for some of us, the size still matters and  15.6"+ laptops are just too big and heavier to move around.
Most of the 14"s are light to move around for a whole day and offer enough power for most of the coding tasks and to run IDEs more or less smoothly. 
In the end, it is up to everyone's preferences - would you like a more portable or more powerful device?

Choosing hardware

A keyboard and screen are important for a work comfort so when choosing a new piece of hardware, pay enough attention to them.

Laptop's screen


Resolution 

Without a doubt, 4K offers a crispier image, even when running at a 200% scale. Usually, these panels offer high brightness and good coverage of the sRGB color space.
All of these pros are paid for by a shorter battery lifetime. Rule of thumb is that the time on battery is reduced by 30 to 50% when compared to the same laptop model using an FHD screen.

Brightness

Choose good brightness - never settle for anything under 300 nits. Today, it is not rare to find panels with 400-500 nits. And if you don't follow the foregoing advice on the matte display, the brightness should be as high as possible - like 500 nits or more.
The worst combination is a dim display with a low sRGB color gamut coverage - for example, Lenovo T480 model offers an FHD display with 250 nits and 65% coverage of the sRGB space. That's inconvenient  - the brightness of the display is low and colors are not as vivid as I would like to have them.

Color space coverage

Make sure the color coverage of the selected model is "good enough". Like 90%+ of the sRGB color space.

Display finish

Most consumer-oriented laptops have a glossy screen. For work purposes, look for the matte surface. The glossy one reflects light so it is more like a mirror and not suitable to be used for an extended period of time. It is true that glossy displays seem to provide vivid colors so it is important to pay attention to good color space coverage.

Where to find the tech spec

Read the laptop's review - especially those on https://www.notebookcheck.net/ site. As a part of each review, they measure the display so it is easy to find out the concrete tech spec of the chosen model or compare a few of them. Be aware that some vendors, like Lenovo, are using different suppliers and therefore, the display specs can vary even for the same model.


Setting Up Windows 10

Scaling settings

Even for an FHD resolution, the text in the native resolution is too small, at least for some people, including myself. Microsoft recommends setting scaling to either  125% or 150% for an FHD resolution. That could be too much, I prefer something between 5 to 15% - it really depends on the overall quality of the hardware, better panels allow for a lower values (like 5%)


Go to Settings -> System -> Display -> Advanced scaling settings. Set up the custom scaling to 112-115. In my opinion, this is the best settings as it provides, at least for me. I am over 40 so my eyes are far from what they once were 20 years ago :-) .

Task bar

As the FHD is wider than higher (1920 to 1080), the vertical space is limited and precious, and as such should be handled with care. It makes no sense to waste it for the taskbar. I always move the Window's taskbar to the right side - even on 25" WQHD monitors. I prefer an always visible taskbar over the hiding it.

Setting up Visual Studio 


Code style 

I am keeping my code width within 120 char limit- meaning no line of code can exceed 120 chars. After all, it results in a cleaner and more readable code. There is a great extension helping with this from on Visual Studio's Marketplace: https://marketplace.visualstudio.com/items?itemName=PaulHarrington.EditorGuidelines.
Install it, open the editor, go to 120 char, right-click and from the context menu choose Guidelines -> Add Guidelines 

Remove navigation 

 Open Options (Tool-> Options - or Alt + T +O), go to Text Editor -> All Languages, C#, uncheck the Navigation Bar.



Hide the menu bar 

Again, there is a helpful and gorgeous extension available from the Marketplace: https://marketplace.visualstudio.com/items?itemName=Poma.MinimalisticView
Become a friend with shortcuts like:

  • Alt - get the menu bar 
  • Ctrl + W + E - error window 
  • Ctrl + W + S - solution window (which can supply the Navigation bar functionality) 
  • Alt + T + O - options dialog

Toolbars

Change the location of the used toolbars from Top (default) to Left. As already written, there is enough space horizontally on the screen. Go to Tools - Customize and set up the  location:

Learn


Learn shortcuts

For speedy work, all the interruptions must be limited. For example, it is better to keep your fingers on the keyboard and avoid to use an external mouse, a touchpad or even the TrackPoint.

Conclusion

Just by following this simple advice, it is possible to get 51 lines visible in the editor window. Which is pretty close to what I am used to from bigger (and heavier) laptops. For them, it is possible to have between 52 to 63 line, depening on your preferences.



C# - making null check fluent

Let's have the following piece of code, taken from a real codebase. Its main purpose is to find a person from a list of persons.  The excerpt was slightly simplified to make it shorter and comprehensive for the purpose of this article as in a real application, the search would be done using the Entity Framework and IQueryable and it would be a little bit complicated with more wheres, includes, and others lambda expressions).
using System;
using System.Collections.Generic;
using System.Linq;
 
namespace FluentSyntax
{
    class Person
    {
        public string FirstName { get; set; }
 
        public string LastName { get; set; }
    }
 
    class Program
    {
        private static List persons = new List
        {
            new Person {FirstName = "Joe", LastName ="Black" },
            new Person {FirstName = "Bill", LastName ="House"}
        };
 
        static void Main(string[] args)
        {
            var personsToFind = new[] { "Bla", "Mar", "Dow", "H" };
 
            foreach(var personToFind in personsToFind)
            {
                try
                {
                    Console.WriteLine($"{personToFind}: {FindPerson(personToFind).LastName}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{ personToFind}: {ex.Message}");
                }
            }
        }
  
        private static Person FindPerson(string lastNameStartsWith)
        {
            var person =
                persons
                    .Where(p => p.LastName.StartsWith(lastNameStartsWith))
                    .FirstOrDefault();
 
            if (person == null)
            {
                throw new Exception("Person not found.");
            }
 
            return person;
        }
    }
}

Issue

The FindPerson method contains a null check occupying four lines. Any unnecessary code lines make our code harder to read and understand. In real codebase, such a code structure is repeated over and over many times in the real codebase, once to check person, somewhere else to check cards, registered cars and so on. So it would be desirable to make this part shorter or more compact.

Just one line

First of all, let's reduce the number of lines.  To achieve that, the following extension method was defined:
public static class Extensions
{
    public static void ThrowIfNull<texception>(
        this object value,
        string message) where TException : Exception
    {
       if (value == null)
       {
           ThrowException<texception>(message);
       }
    }

    private static void ThrowException<exception>(string message) where TException : Exception
    {
        object[] argValue;

        if (typeof(TException).Equals(typeof(ArgumentNullException))
            ||
            typeof(TException).Equals(typeof(ArgumentOutOfRangeException)))
        {
            argValue = new object[] { null, message };
        }
        else
        {
            argValue = new object[] { message };
        }

        throw (TException)Activator.CreateInstance(typeof(TException), argValue);
    }
}

Using this extension method, the find a person code can be changed as follows:
private static Person FindPerson(string lastNameStartsWith)
{
    var person =
        persons
            .Where(p => p.LastName.StartsWith(lastNameStartsWith))
            .FirstOrDefault();

    person.ThrowIfNull<Exception>("Person not found");

    return person;
}

Undoubtedly, it is better now as there is only one additional line in the code. But wouldn't it be better to make it a part of the lambda search expression? In other words, add support for the fluent syntax?

Make it fluent

Let's explore this idea by changing the ThrowIfNull extension method:
public static TObject ThrowIfNull<TException, TObject>(
    this TObject value,
    string message) where TException : Exception
{
    if (value == null)
    {
        ThrowException<TException>(message);
    }

    return value;
}

The method to find a person  must be updated to:
private static Person FindPerson(string lastNameStartsWith)
{
    var person =
        persons
        .Where(p => p.LastName.StartsWith(lastNameStartsWith))
        .FirstOrDefault()
        .ThrowIfNull<Exception>("Person not found");

    return person;
}

The code is shorter now, which is good, however, it requires the coder to specify the return type in the code(<Exception, Person>). It would be desirable to be able to avoid it in the code.
To achieve that, the method should be split into two methods, one of them checking for null, the second one to create an exception: Here are these two new methods:
public static Action Throw<texception>(string message) where TException : Exception
{
    return () => ThrowException<texception>(message);
}

public static TObject IfNull<tobject>(this TObject value, Action action)
{
    if (value == null && action != null)
    {
        action();
    }

    return value;
}

Once implemented and after adding the following directive at the top of the code file after the usings:

using static FluentSyntax.Extensions;

we can change the code to:
private static Person FindPerson(string lastNameStartsWith)
{
    var person =
        persons
            .Where(p => p.LastName.StartsWith(lastNameStartsWith))
            .FirstOrDefault()
            .IfNull(Throw<Exception>("Person not found"));

    return person;
}

Conclusion

What was wrong with the first implementation? Remember the single responsibility principle - the method should be responsible for a single part of the functionality (SRP, part of the SOLID rules).
This rule was broken by the original method as it actually did two things - check for null and creating/throwing an exception.
It is fixed in the final implementation by moving the functionality into two independent methods. The first one checks for null and invokes an unspecified action, the second one provides the actual explicit action.

P.S: the method can be simplified more:
private static Person FindPerson(string lastNameStartsWith)
{
    return
        persons
            .FirstOrDefault(p => p.LastName.StartsWith(lastNameStartsWith))
            .IfNull(Throw<Exception>("Person not found"));
}

Note: never throw a general common exception, use the derived, specialized exception like the NullReferenceException and similar.