This is Part II. Part I is
The nameof operator
operator is another feature that was summarily dismissed as a tag-along to a bigger, more unwieldy feature: the legendary
PropertyInfo info = infoof(Point.X);
string name = nameof(Point.X); // "X"
operator returns reflection information for a given language element,
just returns its name as a string. While this seems quite similar at the surface, there is actually quite a big difference when you think about it more deeply. So let’s do that!
First of all, let’s just observe that when people ask for the
operator, they are often really just looking to get the name. Common scenarios include throwing
s (where the parameter name must be supplied to the exception’s constructor), as well as firing
events when properties change, through the
The reason people don’t want to just put strings in their source code is that it is not refactoring safe. If you change the name, VS will help you update all the references – but it will not know to update the string literal. If the string is instead provided
by the compiler or the reflection layer, then it will change automatically when it’s supposed to.
At a time when we are trying to minimize the use of reflection, it seems wrong to add a feature,
, that would contribute significantly to that use.
would not suffer from that problem, as the compiler would just replace it with a string in the generated IL. It is purely a design time feature.
There are deeper problems with
, pertaining to how the language element in question is uniquely identified. Let’s say you want to get the
for an overload of a method
. How do you designate which overload you are talking about?
void M(int x);
void M(string s);
var info = infoof(M…); // Which M? How do you say it?
We’d need to create a whole new language for talking about specific overloads, not to mention members that don’t have names, such as user defined operators and conversions, etc.
does not seem to have that problem. It is only for named entities (why else would you want the name), and it only gives you the name, so you don’t need to choose between overloads, which all have the same name!
All in all, therefore, it seems that the concerns we have about
do not apply to
, whereas much (most?) of its value is retained. How exactly would a
We would want the operator to be syntactically analogous to the existing
. This means we would allow you to say
in a way that at least sometimes would parse as an invocation of a method called
. This is ambiguous with existing code only to the extent that such a call binds. We would therefore take a page out of
’s book and give priority to the unlikely case that this binds as a method call, and fall back to
operator semantics otherwise. It would probably be ok for the IDE to always highlight
as a keyword.
The operand to
has to be “something that has a name”. In the spirit of the
operator we will limit it to a static path through names of namespaces, types and members. Type arguments would never need to be provided, but in every name but the last you may need to provide “generic dimension specifiers” of the shape
to disambiguate generic types overloaded on arity.
The grammar would be something like the following:
is taken from the definition of
. Note that it always ends with an identifier. Even if that identifier designates a generic type, the type parameters (or dimension specifiers) are not and cannot be given.
It is an error to specify an operand to
that doesn’t “mean” anything. It can designate a namespace, a type, a member, a parameter or a local, as long as it is something that is in fact declared.
The result of the
expression would always be a string containing the final identifier of the operand. There are probably scenarios where it would be desirable to have a “fully qualified name”, but that would have to be constructed from the
parts. After all, what would be the syntax used for that? C# syntax? What about VB consumers, or doc comments, or comparisons with strings provided by reflection? Better to leave those decisions outside of the language.
We like the
operator and see very few problems with it. It seems easy to spec and implement, and it would address a long-standing customer request. With a bit of luck, we would never (or at least rarely) hear requests for
While not the highest priority feature, we would certainly like to do this.