Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you use nameof when hidden by in scope member?

Tags:

c#

nameof

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.

like image 561
InBetween Avatar asked Mar 10 '23 00:03

InBetween


1 Answers

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.

like image 97
Eric Lippert Avatar answered Mar 20 '23 21:03

Eric Lippert