TL;博士 - 使用Child
以上Parent
是在局部范围内是优选的。它不仅有助于提高可读性,而且还必须确保重载的方法解析正常工作并有助于实现高效的编译。
在当地范围内
Parent obj = new Child(); // Works
Child obj = new Child(); // Better
var obj = new Child(); // Best
从概念上讲,它与维护尽可能多的类型信息有关。如果我们降级到Parent
,我们实际上只是在剥离可能有用的类型信息。
保留完整的类型信息具有四个主要优点:
- 向编译器提供更多信息。
- 向读者提供更多信息。
- 更干净,更标准化的代码。
- 使程序逻辑更易变。
优势1:向编译器提供更多信息
表观类型用于重载方法解析和优化中。
示例:重载的方法解析
main()
{
Parent parent = new Child();
foo(parent);
Child child = new Child();
foo(child);
}
foo(Parent arg) { /* ... */ } // More general
foo(Child arg) { /* ... */ } // Case-specific optimizations
在上面的示例中,两个foo()
调用均有效,但在一种情况下,我们获得了更好的重载方法解析。
示例:编译器优化
main()
{
Parent parent = new Child();
var x = parent.Foo();
Child child = new Child();
var y = child .Foo();
}
class Parent
{
virtual int Foo() { return 1; }
}
class Child : Parent
{
sealed override int Foo() { return 2; }
}
在上面的示例中,两个.Foo()
调用最终都调用了return的相同override
方法2
。只是,在第一种情况下,有一个虚拟方法查找来找到正确的方法。在第二种情况下不需要此虚拟方法查找,因为该方法的sealed
。
感谢@Ben,他在回答中提供了类似的示例。
优势2:给读者更多信息
知道确切的类型(即)Child
,可以为正在阅读代码的任何人提供更多信息,从而使查看程序的工作变得更加容易。
当然,也许这并不重要,因为无论是实际的代码parent.Foo();
和child.Foo();
有意义,但对于某人来说看到的第一次代码的详细信息,只是普通的帮助。
此外,根据您的开发环境,IDE可能会提供Child
比以下工具更有用的工具提示和元数据:Parent
。
优势3:更清洁,更标准化的代码
我最近看到的大多数C#代码例子,var
基本上是简写Child
。
Parent obj = new Child(); // Sub-optimal
Child obj = new Child(); // Optimal, but anti-pattern syntax
var obj = new Child(); // Optimal, clean, patterned syntax "everyone" uses now
看到一个非var
声明语句看起来很像。如果有某种情况下的原因,那太棒了,但否则看起来是反模式的。
// Clean:
var foo1 = new Person();
var foo2 = new Job();
var foo3 = new Residence();
// Staggered:
Person foo1 = new Person();
Job foo2 = new Job();
Residence foo3 = new Residence();
优势4:更具可变性的原型程序逻辑
前三个优势是最大的优势。这是更多的情况。
不过,对于像其他人一样使用代码的人也使用Excel,我们会不断更改代码。也许我们不需要Child
在此版本的代码中调用唯一的方法,但是稍后我们可能会重新使用代码或重新编写代码。
强类型系统的优点在于,它为我们提供了有关程序逻辑的某些元数据,从而使可能性更加明显。这在原型制作中非常有用,因此最好将其保留在尽可能的位置。
摘要
使用Parent
混乱的重载方法分辨率,会抑制某些编译器优化,从读取器中删除信息,并使代码更丑陋。
使用var
确实是必经之路。它快速,干净,有模式,可帮助编译器和IDE正确完成其工作。
重要提示:这个答案是关于Parent
对Child
在方法的局部范围。对于返回类型,参数和类字段,Parent
vs。的问题Child
非常不同。