Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if union case property was named by compiler

Tags:

.net

f#

F# lets you optionally name union case properties. If you don't, the compiler will automatically pick a name for you during compilation (Item1...n).

type Foo =
| Nothing
| AutomaticallyNamed of string
| Named of nameOfProperty: string

The only thing I could come up with was a simple string compare on the name on whatever GetFields returns.

let testCase = Named "bar"
let caseInfo, _ = FSharpValue.GetUnionFields(testCase, typeof<Foo>)

caseInfo.GetFields()

Is there a more reliable way to determine if a name was generated by the compiler?

like image 362
Brunner Avatar asked Feb 01 '26 18:02

Brunner


1 Answers

Quite interesting question. It turns out that the case fields are not in fact stored as a System.Tuple, but are compiled into standard .NET properties with a backing field on the nested class representing the union case.

If you look at the generated code in ILSpy or similar disassembler, you'll find a few curious bits and pieces:

  1. There's nothing on the property to tell you that it has a user-provided name, so if you're looking for a nice and clean solution here, you're out of luck.

  2. However, when a field has a user-provided name, the backing field (not the property) will be generated with the underscore in front of the name (i.e. _nameOfProperty). So you can drill down to it using reflection if you call GetMembers on the union case nested class, providing NonPublic ||| Instance binding flags.

  3. Alternatively, the same names are used for constructor arguments to the single non-public constructor of the union case class, so you can get the same information by inspecting the parameters of the constructor - GetConstructors again with non-public binding flags, then GetParameters.

  4. Things are never this simple though - there's one caveat here in that if you actually name your field using the naming scheme the compiler uses - i.e. Item42 - it will get compiled without underscore, as if it was assigned by the compiler. Though luckily compiler is smart enough to skip the ordinal you've already used.

So you could in theory detect if the name is user-provided or not, but it's cumbersome, circumstancial and depends on internal implementation details that are not guaranteed to stay as they are.

like image 76
scrwtp Avatar answered Feb 04 '26 16:02

scrwtp



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!