如果我在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
答案 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
的字段。现在为什么出现这个警告,因为一个是方法而另一个是字段,答案在文档中。
通常,引入的常量,字段,属性或类型 类或结构隐藏了共享它的所有基本类成员 名称强>
和
类或结构中引入的方法隐藏属性,字段和 在基类中共享该名称的类型。它也隐藏了所有基础 具有相同签名的类方法。
更多解释:
您的警告与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
关键字将消除警告,并确保您(作为开发人员)知道您在这里做了什么。