A member-access consists of a primary-expression or a predefined-type,
followed by a ?.? token, followed
by an identifier.
member-access:
primary-expression . identifier
predefined-type . identifier
predefined-type: one of
bool byte char decimal double float int long
object sbyte short string uint ulong ushort
A member-access of the form E.I, where E is a primary-expression or a
predefined-type and I is an
identifier, is evaluated and classified as follows:
?If E is a namespace and I is the name of an accessible member of that
namespace, then the result is that
member and, depending on the member, is classified as a namespace or a type.
?If E is a predefined-type or a primary-expression classified as a type,
and a member lookup (?4.3) of I
in E produces a match, then E.I is evaluated and classified as follows:
If I identifies a type, then the result is that type.
If I identifies one or more methods, then the result is a method group with
no associated instance
expression.
If I identifies a static property, then the result is a property access
with no associated instance expression.
If I identifies a static field:
?If the field is readonly and the reference occurs outside the static
constructor of the class or
struct in which the field is declared, then the result is a value, namely
the value of the static field
I in E.
?Otherwise, the result is a variable, namely the static field I in E.
If I identifies a static event:
?If the reference occurs within the class or struct in which the event is
declared, and the event
was declared without event-accessor-declarations (?7.7), then E.I is
processed exactly as if I
was a static field.
?Otherwise, the result is an event access with no associated instance
expression.
If I identifies a constant, then the result is a value, namely the value of
that constant.
If I identifies an enumeration member, then the result is a value, namely
the value of that enumeration
member.
Otherwise, E.I is an invalid member reference, and a compile-time error
occurs.
?If E is a property access, indexer access, variable, or value, the type
of which is T, and a member lookup
(?4.3) of I in T produces a match, then E.I is evaluated and classified as
follows:
First, if E is a property or indexer access, then the value of the property
or indexer access is obtained
(?4.1.1) and E is reclassified as a value.
If I identifies one or more methods, then the result is a method group with
an associated instance expression
of E.
If I identifies an instance property, then the result is a property access
with an associated instance expression
of E.
If T is a class-type and I identifies an instance field of that class-type:
?If the value of E is null, then a System.NullReferenceException is thrown.
Chapter 14 Expressions
141
?Otherwise, if the field is readonly and the reference occurs outside an
instance constructor of
the class in which the field is declared, then the result is a value,
namely the value of the field I
in the object referenced by E.
?Otherwise, the result is a variable, namely the field I in the object
referenced by E.
If T is a struct-type and I identifies an instance field of that
struct-type:
?If E is a value, or if the field is readonly and the reference occurs
outside an instance
constructor of the struct in which the field is declared, then the result
is a value, namely the
value of the field I in the struct instance given by E.
?Otherwise, the result is a variable, namely the field I in the struct
instance given by E.
If I identifies an instance event:
?If the reference occurs within the class or struct in which the event is
declared, and the event
was declared without event-accessor-declarations (?7.7), then E.I is
processed exactly as if I
was an instance field.
?Otherwise, the result is an event access with an associated instance
expression of E.
?Otherwise, E.I is an invalid member reference, and a compile-time error
occurs.
14.5.4.1 Identical simple names and type names
In a member access of the form E.I, if E is a single identifier, and if the
meaning of E as a simple-name
(?4.5.2) is a constant, field, property, local variable, or parameter with
the same type as the meaning of E as
a type-name (?0.8), then both possible meanings of E are permitted. The
two possible meanings of E.I are
never ambiguous, since I must necessarily be a member of the type E in both
cases. In other words, the rule
simply permits access to the static members and nested types of E where a
compile-time error would
otherwise have occurred. [Example: For example:
struct Color
{
public static readonly Color White = new Color(?);
public static readonly Color Black = new Color(?);
public Color Complement() {?}
}
class A
{
public Color Color; // Field Color of type Color
void F() {
Color = Color.Black; // References Color.Black static
member
Color = Color.Complement(); // Invokes Complement() on Color
field
}
static void G() {
Color c = Color.White; // References Color.White static
member
}
}
Within the A class, those occurrences of the Color identifier that
reference the Color type are underlined,
and those that reference the Color field are not underlined. end example]