C# 7.3 Features : Tuple Comparison & Generic Constraints

C# 7.3 is another minor roll-out that brings along with ‘seemingly minor’ improvement, but ones that definitely opens new opportunities. In this blog post, we will explore  two features that are introduced in 7.3

Tuple Comparison

C# 7.x had already made tuple an immensely powerful tool with a variety of features, and the latest minor roll-out takes that a step higher. Prior to C# 7.3, we could not use ‘==’ and ‘!=’ operators to compare tuples. C# 7.3 improvements makes it possible for us to do the same.
var tuple1 = (3,4);
var tuple2 = (5,6);

if(tuple1 == tuple2)
{
// Do something
}

Generic Constraints

The way I see it, this might turn out one feature which find more fans.  Generics, since its introduction in C# 2.0, was always handicapped by its in ability to constraint the accepted generic type must be an enum.
void TestMethod(TSource param) where TSource : Enum
{
// Do something
}
C# 7.3 also allows you use following constraints
  • unmanaged
  • delegate
That’s it for now, we will explore more features soon.

Custom Tooltip in Oxyplot

Working with OxyPlot sometimes throw these interesting problems, mainly due to lack of documentation. One of the recent challenges involved creating a custom tooltip, which at the hindsight, was pretty straightforward – only if the developers had continued their effort in completing the documentation.

 

Alright back to out problem. Oxyplot, by default provides a neat little tooltip for the Data Points in the graph. On most occasions, these are more than enough. On others, you need to tweak the tooltip a bit more to include additional information.

 

If you browse through the Series Class (LineSeries, BarSeries etc), you would notice it has a property named TrackerFormatString. This is the key to unlocking the tooltip. For sake of example, we will examine the LineSeries in this post. By default, following is the format of TrackerFormatString

 

"{0}\n{1}: {2:0.###}\n{3}: {4:0.###}"

 

Where
{0} = Title of Series
{1} = Title of X-Axis
{2} = X Value
{3} = Title of Y-Axis
{4} = Y Value

Some of the basic customization can happen within the TrackerFormatString property itself, say, suppose you want format the values to display only 2 decimal places. This again would be sufficient to cover a lot of cases.

However, at times, you might be interested to display additional information. Unfortunately the DataPoint class has only two properties, which you could use for loading your data. This cripples you desire to add a third value associated with the DataPoint in addition to X & Y, especially if you notice that the DataPoint is a sealed class and Series.Points.Points.AddRange accepts only DataPoints as parameter.

Thankfully, Oxyplot developers has left another door open while closing the DataPoint class. It allows you to assign the Points to Series using the Series.ItemSource Property, which accepts an IEnumerable. The only criteria for your IEnumerable is to the type needs to implement IDataPointProvider.
Let’s go ahead and implement our demo class.

 

public class CustomDataPoint : IDataPointProvider
{
  public double X { get; set; }
  public double Y { get; set; }
  public string Description { get; set; }
  public DataPoint GetDataPoint() => new DataPoint(X, Y);

  public CustomDataPoint(double x,double y,string description)
  {
    X = x;
    Y = y;
    Description = description;
  }
}

var points = new CustomDataPoint[]
{
  new CustomDataPoint(5,12,"Info 1"),
  new CustomDataPoint(6,10,"Info 2"),
  new CustomDataPoint(7,9,"Info 3"),
  new CustomDataPoint(8,13,"Info 4"),
  new CustomDataPoint(9,14,"Info 5"),
  new CustomDataPoint(10,10,"Info 6")
};

And now we will use the ItemSource property to assign the points to Series. We will also use the TrackerFormatString to format our tooltip to display additional information.

var seriesVisible = new OxyPlot.Series.LineSeries();
seriesVisible.ItemsSource = points;
seriesVisible.TrackerFormatString = "X={2},\nY={4},\nAdditionalInfo={Description}";

That’s it and we have our additional information displayed in tooltip. Go and run your application

OxyPlotWithCustomTooltip

Linq : Significance of AsEnumerable

While LINQ provides a big umbrella to query in-memory as well as remote collections alike (part of the benefit is having a standard vocabulary to query any collection), there are subtle differences, which rises from the way the two classes of Linq queries work.

A Linq query over in-memory collections usually work over the IEnumerable extensions, while the queries over LINQ to SQL work over the IQueryable extensions. This is a subtle difference, considering the IQueryable inherits from IEnumerable, but the consequences can strike you if you are not expecting them.

IQuerable approach (remote query) translates the entire query to the corresponding Database Query and execute it over in the Server.

However, this means one needs to be aware that this approach has its limitations set to the Database Server capabilities, for example, Linq To Sql, is to restricted to the capabilities of the concerned Database Server.

Consider the following example. The following code attempts to read data from Exam table, where the Description Field contains a Date string. For making our life easier, we are using a RegEx.
Regex regex = new Regex(@"([01]?[0-9]|2[0-3]):[0-5][0-9]");
var output = Exams.Take (100).Where(x=> regex.IsMatch(x.Description));

However, this would result in an error as Sql doesn’t recognize regular expression, which means, Linq wouldn’t be able to convert the statement to an equivalent Sql Query.

This is where the IEnumerable.AsEnumerable method comes into picture. Let’s examine the source of the extension method in Referencesource.

  public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
   return source;
}

The method as such, if you were to look up in reference source, might be doing very less, but its significance in the scheme of things is no less important. What it does is that it converts an IQueryable to IEnumerable and there by splits the Linq statement into 2, one that executes on the Server and other, as local collection.

For example, to fix our code above, we would need to change the statement as following.

var output = Exams.Take (100).AsEnumerable().Where(x=> regex.IsMatch(x.Description));

This would split our query into two. The first part would query the Database to fetch 100 rows from Exam table. The second part would then query the resulting collection locally using the Regex expression.

Although the differences are pretty evident once you use it, it is pretty useful to visit the backing classes to understand why it behaves so.

 

Code Smells : Dispensable

Continuing on our discussion on Code Smells and Refactoring techniques, we will discuss Dispensable in this post.

Dispensables are avoidable components whose absence would make the code much more cleaner, readable and efficient.

Comments

A joke is not a good one if needed to be explained. A similar philosophy holds for code as well. If you feel that the code requires comments to understand, then it is better to refactor  it such a way that it eliminates the need of comments.

You could start with refactoring techniques like Rename Method, Rename Variable, along Extract Variable and Extract Method. Quite often using asserts (introduce assertions) can also aid in increasing the readability of the code.

Duplicate Code

When you have a larger team, there is a distinct possibility that two developers working different parts of the project might end up developing similar/same method. The similarity could could be subtle as well, where similarity is visible to only in certain parts of code, while performing the same job.

Extract Method, Extract superclass and Extract class are some of the refactoring methods that can be applied. If two methods do same job but using different algorithms, refactoring techniques like Substitute algorithm (Strategy Pattern) can be applied. Similarly, if the duplicated code is only visibly similar, but isn’t quite identical, Form Template Method technique (Template Method Pattern) can be applied.

Lazy Class

There could exist classes in your code which has become obsolete or the functionalities are near-useless, you could employee techniques like Inline Class to remove it.

Maintaining code is expensive and any unused code should be carefully eliminated.

Data Class

Classes are identified by two factors – Properties and Behaviours.  If you stumble upon a class that has only properties, then it is a good candidate for Data Class code smell.

 The first step you need to take is to review the client code that uses the class, and review if the functionality could exist in the Data Class itself. You could also review if the conventional collection such as Arrays could be used to store the Data in the class, thus eliminating the need for class.

Dead Code

Dead Code is often resultant of changing requirements/specifications, and a development team that was unsure/lazy to clean up the code. A good IDE such as the Visual Studio can aid in detecting such code and can be eliminated.

Remember, it doesn’t need to be a method, the dead code could also be a unused parameter, which can be eliminated using the Remove Parameter refactoring technique.

Speculative Generality

How often have we been guilty of creating functionality in anticipation of future requirements, but ended up never having to use them ? It is a common trait in teams, which is highly infectious and needs to be avoided. XP Principles like YAGNI, KISS can be highly useful in this regard in educating the team to avoid such pitfalls.

Refactoring techniques such as Collapse Hierarchy an Inline class can be used for eliminating such code.

Design Pattern : Memento Pattern

Memento Design Pattern allows to capture internal state of an object in an external object and restore it to the desired checkpoint when required, all the while being in compliance with encapsulation.

The Memento Design Pattern comprises of 3 actor classes.

  • Originator : The class which needs to have the ability to store its internal state and restore itself to checkpoint when required.
  • Memento : Contains the internal state of Originator.
  • Caretaker : The shepherd class who is in charge of storing and restoring Originator from Memento.

Let’s go ahead and implement the actor classes

Classic Approach

public class Memento
    {
        public string FName { get; set; }
        public string LName { get; set; }

    }

 public class Caretaker<TSource>
    {

        private IList<Memento> _stateMemory;

        public Caretaker()
        {
            _stateMemory = new List<Memento>();
        }

        public Memento GoBack(int level) =>  _stateMemory.Reverse().Skip(level-1).First();

}

 public class Originator: IOriginator
    {
        public string FName { get; set; }
        public string LName { get; set; }

        public void RestoreState(Memento memento)
        {
            this.FName = memento.FName;
            this.LName = memento.LName;
        }

        public Memento Save()
        {
            return new Memento() {
                LName = this.LName,
                FName = this.FName
            };
        }

    }

The above code showcases the implementation of Memento in its simplest form. You could step up things by making the Memento generic so that it can be reused with other classes as well.

Generic Memento with Serialization.

Instead of defining each properties of the Originator class, we could create a completely generic version by utilizing the powers of serialization.

In the following example implementation of Memento class, I have used ProtoBuf for serializing the class.

public class Memento<TSource>
    {
        private byte[] _state;

        public Memento(TSource data)
        {
            using(var stream = new MemoryStream())
            {
                ProtoBuf.Serializer.Serialize<TSource>(stream, data);
                _state = stream.ToArray();
            }
        }

        public TSource Value
        {
            get
            {
                using(var stream = new MemoryStream(_state))
                {
                    return ProtoBuf.Serializer.Deserialize<TSource>(stream);
                }
            }
        }
    }

The entire source code shown in this example are available in my GitHub.

Quick Intro to Protobuf

Protobuf-net is a .net adaption of Google’s Protocol Buffers and is generally considered to be a really fast serialization/deserialization library.  The target serializable classes are decorated with mainly 3 attributes.

ProtoContract
The target class is decorated with the ProtoContract attributes, indicating that the class can be serialized.

ProtoMember(N)
The ProtoMember attribute indicates the field that will be serialized, while the number N denotes the order in which the property would be serialized. By default, the properties would be serialized in alphabetical order.

ProtoIgnore
As the name suggests, the ProtoIgnore attributes is used to indicate the properties that needs to be ignored while serializing.

Let’s create the example class which we would be serializing.

[ProtoContract]
public class Student
{
  [ProtoMember(1)]
  public string Name { get; set; }
}

In order to serialize the class, you would be using the Static method Serialize.

var stOriginal = new Student() { Name = "jia" };
byte[] array;
           
using (var stream = new System.IO.MemoryStream())
{
   ProtoBuf.Serializer.Serialize(stream, stOriginal);
   array = stream.ToArray();
}

Similarly, the static method Deserialize can be used to deserialize the object back.

Student stDeserialized;
using (var stream = new System.IO.MemoryStream(array))
{
  stDeserialized = ProtoBuf.Serializer.Deserialize(stream);
}

Easy as that !! Happy Coding !!

Pass Property as Expression

I recently needed to pass a property of a class as an expression to a method and read value from it. I found the code that I finally ended up interesting and thought it might be useful to share it here.

void Main()
{
var instance = new Test();
instance.FName= "jia";
PrintMethod(x=>x.FName,instance);
}
public void PrintMethod(Expression<Func> action,dynamic instance)
{
var memberExpr = action.Body as MemberExpression;
var propInfo = memberExpr.Member as PropertyInfo;
var value = propInfo.GetValue(instance);
Console.WriteLine(value);
}

class Test
{
public string FName{get;set;}
public string LName{get;set;}
}

It might look I could have passed the value directly instead of as an expression, but the real life scenario was much complex than one demonstrated in the example.

Sneak Peak at Response Files (.rsp)

The Visual Studio has evolved so much that anyone hardly uses the CSC.exe tool and command line switches any longer. But there could be days when you are forced to opt for CSC.exe and the biggest woe is the huge list of switches/parameters that you need to associate each time you want to compile using csc.exe.

The response files (*.rsp) provides a cleaner way to find a solution for this problem, inevitably also taking caring of accidentally missing parameters. Response files is plain text files which contains a set of switches you would like to apply to your compilation command. Let’s consider the example.

csc.exe /out:jia.exe /t:exe program.cs

We have opted for a simple example. In real life, you could be referring to a bag full of dependencies, which you would have to include using the /r switch. But for sake of example, we will stick to simple example mentioned above. We will now write out response file to include the /out and /t switches.

/out:jia.exe
/t:exe

We will name it as “app.rsp”. Now, to compile our cs file, we would need to specify the rsp file using the @ prefix.

csc.exe @app.rsp program.cs

The .Net framework uses a similar approach internally by employing a global response file (csc.rsp). This is the reason we could compile the source files even when skip referencing commonly used dlls in command.

Oxyplot and DateTime Axis

Anyone who has just been introduced to OxyPlot and had to deal with a graph comprising of a Time/DateTime axis might find themselves in a corner. The first thing you would notice is that the DataPoint structure accepts only double and that means trouble, especially with a not-so-exhaustive documentation the tool supports. But if you keep persisting and look around a bit, you will soon notice that the OxyPlot developers has done a fair bit of job to ensure TimeAxis (and many more) are possible. The DateTimeAxis Class enables you to add a DateTime object to your PlotModel.

But prior to jumping to your Axes, you need to find a solution to add a DateTime to your DataPoint Collection. This is again made possible by the DateTimeAxis class and the ToDouble method.

var  dataPoints = new[]
{
    new DataPoint(DateTimeAxis.ToDouble(new DateTime(2018,1,1,7,23,0)),12),
    new DataPoint(DateTimeAxis.ToDouble(new DateTime(2018,1,1,8,23,0)),9),
    new DataPoint(DateTimeAxis.ToDouble(new DateTime(2018,1,1,10,23,0)),13)
};

Now let’s add the required axes.

MainGraphModel.Axes.Add(new DateTimeAxis()
{
  Maximum = DateTimeAxis.ToDouble(new DateTime(2018, 1, 1, 12, 23, 0)),
  Minimum = DateTimeAxis.ToDouble(new DateTime(2018, 1, 1, 6, 23, 0)),
  Position = AxisPosition.Bottom,
  IntervalType = DateTimeIntervalType.Hours,
  MinorIntervalType = DateTimeIntervalType.Hours
});

 

Oxyplot does look pretty good, only if they had better documentation.