NDepend Blog

Improve your .NET code quality with NDepend

The new .NET 7.0 IParsable<TSelf> interface

November 21, 2022 3 minutes read

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.

 

Comments:

  1. Awesome – great explanations and insights. Could you offer a thought on how to best wrap unit testing around these?

  2. 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.