This is explained in §I.8.5.2 of the ECMA-335 CLI specification:
Generally, names are not unique. Names are collected into groupings called scopes. Within a scope, a name can refer to multiple entities as long as they are of different kinds (methods, fields, nested types, properties, and events) or have different signatures.
CLS Rule 5: All names introduced in a CLS-compliant scope shall be distinct independent of kind, except where the names are identical and resolved via overloading. That is, while the CTS allows a single type to use the same name for a method and a field, the CLS does not.
The way I understand this, it means that you can have two different fields with the same name in the same type, but they have to have a different signature, i.e. different type. So, if you have two fields string x
and int x
, that's okay according to the CLI specification. It's not okay according to the Common Language Specification (CLS), but that's basically just a set of rules that makes language interoperability easier.
On the other hand, a type with two fields with the same name and type is not legal and if you run PEVerify on an assembly with a type like that, it indeed fails verification:
[MD]: Error: Field has a duplicate, token=0x04000002. [token:0x04000001]
[MD]: Error: Field has a duplicate, token=0x04000001. [token:0x04000002]
For some reason, it seems the CLR does not make this check, so it allows such invalid types. The C# compiler is also able to handle such types, it seems it chooses one of the two fields and uses that.