But it sure all adds up.
Switching for a codebase might not be a wise move for many reasons. But writing new code doesn't have those excuses.
Actually workflows are the closest to a "killer" feature but C# took the most popular, async, and hard-coded it in.
I'm not sure how new List<string> { "a", "b" } is more readable than new List<_> {"a", "b"), but hey, sure, if you want to argue type inference is bad, go for it. F# also lacks loop constructs like break/continue.
I don't feel I've misrepresented C# at all to make it look bad. I've written a lot of C# code and a fair amount of F# code. Line by line, char-by-char, expression-by-expression, F# is simply much less code. Those examples are just things off the top of my head, from real codebases.
C#'s alright, because the competition (like Java) is laughable. So in that sense, it's "great". In absolute terms, it doesn't measure up (and this isn't a secret, bit-by-bit C# adopts features F# proved out.)
Units-of-measurements are implemented via erasure, yes. How would you represent float<m> externally to make it available to common types, but without losing performance? The compiler consuming them would need to be aware of it. And at runtime, you certainly don't want extra overhead, and I don't think the CLR has any efficient way of exposing primitives with additional type info. It's an unfortunate tradeoff.
1) Simply write a quick extension method (not ideal but not a reason to switch languages):
2) Simply use the appropriate built-in method: 3) It's a matter of taste. Not a bad feature, but not a killer one either.