意外的C#警告:实例成员在基类上隐藏静态方法

时间:2014-08-05 16:43:51

标签: c#

如果我在C#中遇到编译器错误,我很好奇。 (我使用的是Visual Studio 2013 Update 2.还没有Roslyn。)

以下代码会产生意外警告。我认为,Year字段(或属性)不应该在基类上隐藏静态Year方法,因为两者的调用方式非常不同 - 一个在实例变量上,另一个在类上。我不知道两者如何在名称解析中发生冲突。

我错过了什么?

更新:我知道字段和静态方法具有相同的名称。然而,调用这两件事的方式是完全不同,我不知道怎么会有任何混淆。换句话说,从类型系统的角度来看,公共领域"隐藏"似乎是错误的。基类的公共静态方法。任何人都可以提供实际存在冲突的场景吗?

public class Timeframe
{
    public readonly DateTime From;
    public readonly DateTime To;

    public Timeframe(DateTime from, DateTime to)
    {
        From = from;
        To = to;
    }

    public static YearTimeframe Year(int year)
    {
        return new YearTimeframe(year);
    }

    // .. similar factory methods, e.g. Month and Day, omitted
}

public class YearTimeframe : Timeframe
{
    // WARNING: 'YearTimeframe.Year' hides inherited member 'Timeframe.Year(int)'.
    // (a public property w/ private readonly backing field has same problem)
    public readonly int Year;

    public YearTimeframe(int year)
        : base(
        new DateTime(year, 1, 1),
        new DateTime(year, 12, 31, 23, 59, 59))
    {
        this.Year = year;
    }
}

// .. similar classes, e.g. MonthTimeframe and DayTimeframe, omitted

4 个答案:

答案 0 :(得分:5)

这不是错误。它在规范的第3.7.1.2节中明确定义为警告:

  

类或结构中引入的常量,字段,属性,事件或类型会隐藏所有具有相同名称的基类成员。
  ...
  与从外部作用域隐藏名称相反,从继承的作用域隐藏可访问的名称会导致报告警告。

“他们被调用的方式”并不是非常重要,因为你可以拥有像

这样的东西
public class YearTimeframe : Timeframe
{
    // WARNING: 'YearTimeframe.Year' hides inherited member 'Timeframe.Year(int)'.
    // (a public property w/ private readonly backing field has same problem)
    public readonly int Year;

    public YearTimeframe(int year)
        : base(
        new DateTime(year, 1, 1),
        new DateTime(year, 12, 31, 23, 59, 59))
    {
        this.Year = year;
        Method(Year);
    }

    private static void Method(int y)
    {
        Console.WriteLine("int");
    }

    private static void Method(Func<int, YearTimeframe> f)
    {
        Console.WriteLine("Func");
    }
}

现在调用哪个版本的Method?任何一个都可能有效。答案是在这种情况下,简单名称Year解析为字段,因为它隐藏了基类中的静态方法。

答案 1 :(得分:3)

警告非常清楚,因为在基类中有一个名为Year的方法,在子类中有一个名为Year的字段。现在为什么出现这个警告,因为一个是方法而另一个是字段,答案在文档中。

new Modifier (C# Reference)

  

通常,引入的常量,字段,属性或类型   类或结构隐藏了共享它的所有基本类成员   名称

  

类或结构中引入的方法隐藏属性,字段和   在基类中共享该名称的类型。它也隐藏了所有基础   具有相同签名的类方法。

更多解释:

您的警告与static无关。即使您的基类中的方法是实例方法,您仍然会收到警告。但主要原因是相同名称。当您在子类中引入新字段Year时,它会隐藏所有具有相同名称的基类成员

您可以使用子类中的new修饰符来消除警告,但通常此警告会反映您的代码结构存在问题。最好将方法重命名为GetYear,而不是基类中的Year。 IMO。

答案 2 :(得分:1)

是的,它们都被称为“年”,但一个是静态函数,另一个是属性。您需要使用为编译器添加的“new”关键字才能满意。

public new readonly int Year;

答案 3 :(得分:1)

您无法从Year内部调用静态函数YearTimeframe,您必须在其前面加上该类。

所以

public class YearTimeframe : Timeframe
{
    // WARNING: 'YearTimeframe.Year' hides inherited member 'Timeframe.Year(int)'.
    // (a public property w/ private readonly backing field has same problem)
    public readonly int Year;

    public YearTimeframe(int year)
        : base(
            new DateTime(year, 1, 1),
            new DateTime(year, 12, 31, 23, 59, 59))
        {
            this.Year = year;

            Year();
        }
    }
}

会给你一个编译错误。

你必须用

来调用它
public class YearTimeframe : Timeframe
{
    // WARNING: 'YearTimeframe.Year' hides inherited member 'Timeframe.Year(int)'.
    // (a public property w/ private readonly backing field has same problem)
    public readonly int Year;

    public YearTimeframe(int year)
        : base(
            new DateTime(year, 1, 1),
            new DateTime(year, 12, 31, 23, 59, 59))
        {
            this.Year = year;

            Timeframe.Year();
        }
    }
}
因此警告。 还有

来自外部的

YearTimeframe.Year()将无效。 new关键字将消除警告,并确保您(作为开发人员)知道您在这里做了什么。