On my current project, I had an issue with my register definitions. Quite a few of my DUT's registers where just instances of the same register type. My vr_ad register definitions were generated by a script, based on the specification, a flow that I'm pretty sure is very similar to what most of you also have. Instead of generating a nice regular structure, this script created a separate type for each register instance. What resulted was a flattened structure where I'd, for example, get one instance each of registers SOME_REG0, SOME_REG1, SOME_REG2, instead of three instances of SOME_REG. I was lucky enough to be able to (partly) change the definitions by patching them by hand.
You’re right! This also removes the need to do reflection. I was so fixed on that idea that I forgot about get_reg_by_kind(…).
What I also usually do is define an extra method inside vr_ad_reg, called get_field_by_name(fld_name : string). This basically does what your snippet does (including asserts, etc.). I find it really handy.