NDepend

Improve your .NET code quality with NDepend

The new .NET 7.0 IParsable<TSelf> interface

Parsable of TSelf interface - Copy

As I explained in the post C# 11 static abstract members, C# 11 let’s write static abstract members in interface. This feature was mostly introduced to implement the new .NET 7.0 genetic math library, also explained in this article.

However static abstract members in interface opens the door to a whole new range of syntax possibility. One of this possibility is generic parsing through the new .NET 7.0 System.IParsable<TSelf> interface:

Thanks to this interface and its static abstract methods, it is now possible to have a generic extension method that parses a string to anything. Here is an example of such Parse<T>() method with a class Person implementing IParsable<Person> :

Notes on IParsable<T>

As the code sample above suggests, in .NET 7.0 IParsable<T> is implemented by all numeric types Int32, Byte, Double… but also by other types usually subject to parsing like DateTime, DateOnly or Guid.

One limitation of these new parsing APIs is that it assumes that the entire string is the value. You can easily provides your own parsing interfaces that take the start index as input and returns the number of char consumed. This way one can chain parsing operations on a string:

Alternatively .NET 7.0 provides the similar interface ISpanParsable<T> to parse from any ReadOnlySpan<Char> that typically represents a sub-string.

Generic Parsing before .NET 7.0

Just think about it: there were no easy way to implement generic parsing before .NET 7.0 and C# 11. One could have used Reflection as shown in the code ample below:

But this implementation is slower because of reflection cost. And one certainly doesn’t want a performance penalty each time a parsing occurs.

Even worst, the compile-time safety is not here to prevent calling Parse<T>() on a type T that has no Parse(string):T method.

Generic Factory Pattern

Generic parsing is just an example of the Generic Factory Pattern made possible with C#11 static abstract. We can now have in our code base sweet interfaces like IParsebleFromJson or IParsebleFromXml that promote abstraction and re-use through generic algorithms.

But parsing is not the only use-case of generic factories. The code sample below proposes an extension method BuildVector<TNumeric>() that builds a vector from any array of numerics:

The Curiously Recurring Template Pattern (CRTP)

Actually the syntax interface IParsable<TSelf> where TSelf : IParsable<TSelf> is known in C++ as the Curiously Recurring Template Pattern (CRTP). This syntax allows an interface to declare methods with parameters or return type typed with the concrete type that implements the interface (like Parse(....) that returns a TSelf).

However there is no syntax to enforce that TSelf refers to the type that actually implements the interface. In the screenshot below we can see that class Person : IParsable<Employee> compiles and runs properly. This is why the new rule CA2260 emits a warning in this situation.

Curiously Recurring Template Pattern

Conclusion

This new IParsable<TSelf> interface looks like a small new feature but it’s a tree that hides the forest of a new range of convenient syntaxes based on static abstraction.

 

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.

Comments:

  1. As with all generic impl, these new syntaxes make testing easier since not necessarily all generic types parameter consumed at runtime have to be tested. However if you care for 100% testing coverage (and you should IMHO) all parsing implementation should be thoroughly tested.

Comments are closed.