Earlier quoted context omitted.
Could you actually explain/exemplify any of the gotchas and what's been made better (or is this just handwaving)?
I've been let down by structs in C# repeatedly. First of all, there are no constructor guarantees and you can never fully avoid them representing an illegal state. Which, wouldn't be so bad if there was some kind of post-construction validation, but this also isn't part of the language. This is fine if you hand-roll all your code yourself, but I often use mapping libraries to lower the code footprint and the problems…
Structs are values, classes are entities with encapsulation.
The shape of the state would be structural. Whether or not the data in that shape is valid is behavioral.
Structs are useful when working with spans of memory.
Another example of a good usage of struct is Guid, which is 128 bits of data packed together.
The C# equivalent to Java ‘value class’ would be a class with a struct encapsulated for data. The data is flattened and allocated on the heap like Java. Similarly, escape analysis could stack allocate the class at runtime.