我在看这篇博客文章时有以下问题:
- 我们为什么需要
new
关键字,仅仅是指定隐藏一个基类方法。我的意思是,为什么我们需要它?如果我们不使用override
关键字,我们是否隐藏了基类方法? - 为什么C#中的默认值是隐藏而不是覆盖?设计者为什么要以这种方式实现它?
Answers:
好问题。让我重申一下。
为何完全隐藏另一个方法是合法的?
让我用一个例子回答这个问题。您有CLR v1的接口:
interface IEnumerable
{
IEnumerator GetEnumerator();
}
超。现在,在CLR v2的你有仿制药,你认为“男人,如果在V1恨不有仿制药,我会做这个的通用接口。但我没有。我应该做的东西,现在与它兼容即是通用的,所以这我得到了泛型的好处,而又不会失去与期望IEnumerable的代码的向后兼容性。”
interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> .... uh oh
您将如何调用GetEnumerator方法IEnumerable<T>
?请记住,您希望它在非通用基本接口上隐藏GetEnumerator。除非您明确处于向后兼容的情况,否则您永远都不希望调用该东西。
仅此一点就证明了方法的隐藏。有关方法隐藏的理由的更多想法,请参阅我关于该主题的文章。
为什么没有“新”的隐藏会引起警告?
因为我们希望引起您注意,所以您隐藏了某些东西,并且可能是意外地在做。请记住,您可能是由于别人对基类的编辑而不是您对派生类的编辑而意外隐藏了某些东西。
为什么隐藏没有“新”内容的警告而不是错误?
相同的原因。您可能会意外隐藏了某些东西,因为您刚刚获得了新版本的基类。这事儿常常发生。FooCorp创建基类B。BarCorp使用方法Bar创建派生类D,因为他们的客户喜欢该方法。FooCorp看到了这一点,然后说,嘿,这是个好主意,我们可以将该功能放在基类上。他们这样做并发布了新版本的Foo.DLL,当BarCorp选择新版本时,如果告诉他们他们的方法现在隐藏了基类方法,那就太好了。
我们希望这种情况只是警告而不是错误,因为使其成为错误意味着这是脆性基类问题的另一种形式。C#经过精心设计,以便当有人对基类进行更改时,对使用派生类的代码的影响减至最小。
为什么隐藏而不覆盖默认值?
因为虚拟覆盖很危险。虚拟覆盖允许派生类更改已编译为使用基类的代码的行为。做一些危险的事情,例如做一个超越,应该是您有意识地,有意地做的,而不是偶然的。
如果默认覆盖而不指定override
关键字,则由于名称相等,您可能会意外覆盖基础的某些方法。
.Net编译器策略是为了安全起见而发出警告,只是为了安全起见,因此在这种情况下,如果默认覆盖,则每个覆盖方法都必须发出警告-类似于“警告:检查您是否真正想要覆盖”。
我的猜测主要是由于多接口继承。使用谨慎的接口,两个不同的接口很有可能使用相同的方法签名。允许使用new
关键字将允许您使用一个类创建这些不同的实现,而不必创建两个不同的类。
已更新... Eric给了我一个有关如何改进此示例的想法。
public interface IAction1
{
int DoWork();
}
public interface IAction2
{
string DoWork();
}
public class MyBase : IAction1
{
public int DoWork() { return 0; }
}
public class MyClass : MyBase, IAction2
{
public new string DoWork() { return "Hi"; }
}
class Program
{
static void Main(string[] args)
{
var myClass = new MyClass();
var ret0 = myClass.DoWork(); //Hi
var ret1 = ((IAction1)myClass).DoWork(); //0
var ret2 = ((IAction2)myClass).DoWork(); //Hi
var ret3 = ((MyBase)myClass).DoWork(); //0
var ret4 = ((MyClass)myClass).DoWork(); //Hi
}
}
new
关键字允许您也更改所有从该点子孙的产业基地。
如前所述,方法/属性隐藏使更改方法或属性方面的事情成为可能,而这些事情原本无法轻易更改。一种可能有用的情况是允许继承的类具有读写属性,这些属性在基类中是只读的。例如,假设基类具有一堆名为Value1-Value40的只读属性(当然,真实的类将使用更好的名称)。此类的密封后代具有一个构造函数,该构造函数采用基类的对象并从该对象复制值。此后,该类不允许更改它们。一个不同的,可继承的后代声明了一个称为Value1-Value40的读写属性,该属性在读取时的行为与基类版本相同,但是在写入时允许写入值。
这种方法的一个烦人之处-也许有人可以帮助我-是我不知道一种在同一类中同时遮盖和覆盖特定属性的方法。是否有任何CLR语言允许(我使用vb 2005)?如果基类对象及其属性可以是抽象的,这将很有用,但是这将要求中间类在后代类将其遮蔽之前覆盖Value1到Value40属性。