I recently came across a peculiar issue when using the Regex type “MatchCollection” in .NET Core. Or to be more specific, in a .NET Standard library. And while the fix was simple, it actually was an interesting insight into .NET Core vs .NET Framework, and how the mini-fragmentation we have going on between the two frameworks is hard to document.
First let’s rewind. I started off writing code that was pretty similar to the following :
Regex.Matches(stringText, @"myRegex").Select(x => x.value);
When I wrote this code, I had written it inside a .NET Core project. Pretty simple and for the most part, the Regex part looks exactly the same as it did in .NET Framework. However I then had a need to move this code into a library to be shared across two different projects. Naturally I made the library .NET Standard and suddenly I got the following error.
‘MatchCollection’ does not contain a definition for ‘Select’ and no accessible extension method ‘Select’ accepting a first argument of type ‘MatchCollection’ could be found
Interesting. Same code, different platform (.NET Core vs .NET Standard), and suddenly our innocuous “framework” looking code doesn’t work. What gives?
Well, Here’s the definition of MatchCollection in .NET Core
public class MatchCollection : IList<Match>, IReadOnlyList<Match>, IList
And here’s the definition in .NET Framework.
public class MatchCollection : ICollection
So the .NET Core implementation actually implements more interfaces than that of .NET Framework. Infact because it implements IList<T>, it actually implements IEnumerable<T>. “Select”, is a LINQ method that works with IEnumerable<T>, but not ICollection. So using this in .NET Framework will not work.
But I’m using .NET Standard you say! That’s true but remember, .NET Standard enforces a “minimum” implementation – much like an interface would enforce a minimum requirement on a class. But it doesn’t mean that class can’t go over and beyond. As it so happens, the .NET Standard definition of MatchCollection only requires the implementation of ICollection, but it does not require IEnumerable<T> to be implemented. So you cannot use LINQ methods on a Regex MatchCollection if you are targeting anything other then .NET Core.
I kind of lived with this since it wasn’t such a big deal. But given I couldn’t use IEnumerable<T> methods on my MatchCollection anymore, I headed to the Microsoft Documentation for a couple of examples of how my could should work.
And here’s the actual issue.
The documentation *does not* show the differences between .NET Core and .NET Framework. The .NET Core 3.1 documentation for MatchCollection is found here : https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.matchcollection?view=netcore-3.1
Note that it’s definition as per that documentation is :
public class MatchCollection : ICollection
That is wrong!
As it turns out, in 2018, this issue was raised here : https://github.com/dotnet/docs/issues/5608 which if you follow the trail of tickets, leads you to this ticket : https://github.com/MicrosoftDocs/feedback/issues/226. And right there slapped on the bottom.
Welp. Spamming Autocomplete options instead of reading documentation it is!
I had the same issue with code i wrote with .Net Core and to make it work in both Libraries i needed to use the Cast operator in order to use the Zip() method.
That is weird that they do not show the differences.
Thanks for bringing this to our attention! A community member let us know about some confusion on evaluating the issue you posted above. Please follow the status of this particular bug at https://github.com/MicrosoftDocs/feedback/issues/222.
Awesome Maira! Fingers crossed for the change to come soon!
I’m not going to hold this against the technical writters.
I been having a great time with the amazing documentation with .net core.
But it’s good to know we might seen differences, so be aware!
Cheers.