Consider the following legacy code:
public class Foo
{
public void Blah(string frob)
{
if (frob == null)
throw new ArgumentException("frob");
}
public string nameof()
{
//boring code
}
}
Now imagine part of this code is being refactored, and we want to refactor Blah
in the following way:
public void Blah(string frob)
{
if (frob == null)
throw new ArgumentException(nameof(frob)); //nameof contextual keyword
}
This parser will not choose the contextual keyword nameof
and will resolve to the private method nameof
giving a compile time error (no existing overload). Why? I would understand this if the method was nameof(object o)
.
Is there someway I can make the compiler resolve to the inbuilt nameof
? Do I need to refactor the code renaming the method?
The example above is a very simplified scenario, in truth the nameof
method is used extensively in reflection and it will take time and effort to make sure the renaming has been done correctly everywhere.
This parser will not choose the contextual keyword nameof and will resolve to the private method nameof giving a compile time error (no existing overload). Why?
"Why" questions are vague; I'm going to assume the question means "what are some design considerations taken into account when designing features like this?"
A high-order consideration when creating a new contextual keyword is to ensure that no existing program changes meaning when compiled in the new compiler. For example, when I wrote the code to add var
in C# 3, we were careful to ensure that
class var { public implicit operator var(int x) { ... } }
...
var y = 3;
assigns type var
to y
, and not int
. Even though programs like this are very unlikely, we want to break no one at all.
Similarly, the syntax for yield return
was yield return
and not merely yield
because *no program ever had yield return
in it. But lots of programs might have said yield(123);
Similarly the await
operator only is meaningful when inside an async
method, and from
and select
and so on are meaningful inside query comprehensions.
Thus nameof
must mean an identifier named nameof
if one is in scope, and not the operator. Note that C# does not attempt to backtrack. It does not say "well, its in scope, but that causes an overload resolution error, so I'm going to backtrack and assume that it is the keyword..." No no no, that is terrible reasoning. An identifier nameof
is in scope and therefore this is almost certainly a pre-C# 6 program. The 99.9% likelihood is that every use of nameof
in that program intends to refer to the identifier.
A basic design principle of C# is "if something looks weird, tell the developer so they are aware of the problem." You are now thoroughly aware that there is a serious problem in your program, and now you can attempt to fix it. C# is not designed to find any possible interpretation of your program that compiles, no matter how bizarre and unlikely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With