4

考虑以下遗留代码:

public class Foo
{
    public void Blah(string frob)
    {
        if (frob == null)
            throw new ArgumentException("frob");
    }

    public string nameof()
    {
        //boring code
    }
}

现在想象一下这段代码的一部分正在被重构,我们想Blah通过以下方式重构:

public void Blah(string frob)
{
    if (frob == null)
        throw new ArgumentException(nameof(frob)); //nameof contextual keyword
}

此解析器不会选择上下文关键字nameof,并将解析为nameof给出编译时错误(没有现有重载)的私有方法。为什么?如果方法是 . 我会理解这一点nameof(object o)

有什么办法可以让编译器解析为内置的nameof?我需要重构重命名方法的代码吗?

上面的例子是一个非常简化的场景,实际上该nameof方法在反射中被广泛使用,并且需要花费时间和精力来确保在任何地方都正确地进行了重命名。

4

3 回答 3

8

此解析器不会选择上下文关键字 nameof 并将解析为私有方法 nameof 给出编译时错误(不存在现有重载)。为什么?

“为什么”的问题含糊不清;我将假设这个问题的意思是“在设计这样的功能时考虑了哪些设计考虑因素?”

创建新的上下文关键字时的一个重要考虑是确保在新编译器中编译时现有程序不会改变含义。例如,当我编写要var在 C# 3 中添加的代码时,我们小心地确保

class var { public implicit operator var(int x) { ... } }
...
var y = 3;

将类型分配vary,而不是int。即使这样的程序不太可能发生,我们也不想破坏任何人

yield return类似地, was的语法yield return不仅仅是yield因为 * 没有任何程序yield return在其中。但是很多程序可能会说yield(123);

类似地,运算符仅在方法await内部时才有意义,等等在查询理解中才有意义。asyncfromselect

因此nameof必须表示一个标识符nameof,如果一个在范围内,而不是运算符。请注意,C# 不会尝试回溯。它并没有说“嗯,它在范围内,但这会导致重载解决错误,所以我要回溯并假设它是关键字......”不不不,这是可怕的推理。标识符nameof在范围内,因此几乎可以肯定这是 C# 6 之前的程序。99.9% 的可能性是该程序中的每次使用都nameof打算引用标识符。

C# 的一个基本设计原则是“如果某些东西看起来很奇怪,请告诉开发人员,以便他们意识到问题所在。” 您现在完全意识到程序中存在严重问题,现在您可以尝试修复它。C# 的设计目的不是为了找到任何可能的编译程序解释,无论多么奇怪和不可能

于 2017-02-01T23:11:16.220 回答
0

我猜想反射代码nameof在一个类中搜索可能类似于序列化框架的东西......

在这种情况下,也许最好的临时解决方案是更新该代码以首先搜索一个函数NameOf,如果该函数不存在,则搜索 legacy nameof

这样,您将能够一次找到一个类的代码。

如果您想立即进行完整修复并假设您的自定义nameof函数从不接受任何参数,那么最好的解决方案可能是将所有重命名 nameofNameOf(或您喜欢的任何其他名称),然后在nameof应该使用时修复编译错误。如果您有很多代码并且刚刚开始使用运算符,这将是有意义的nameof

在任何情况下,不遵循 .NET 命名约定是一个坏主意,特别是对于这样的短名称可能会在某些时候成为关键字。

也许进行代码审查也是一个好主意,以便那些编写糟糕代码的人在离开公司之前修复它。

于 2017-02-01T21:01:46.170 回答
-1

无论您是否可以强制代码使用 nameof 关键字而不是内置函数,您都不应该将关键字用作方法名称。重命名方法的名称。

于 2017-02-01T18:53:51.207 回答