使用有效示例隐藏在c#中的方法。 为什么在框架中实现? 什么是真实世界的优势?
任何人都可以用一个有效的例子解释隐藏在C#中的方法的实际用法吗?
如果使用派生类中的new
关键字定义方法,则无法覆盖该方法。 然后它与创建一个具有不同名称的新方法(除了在基类中提到的方法之外)相同。
有没有具体的理由使用new
关键字?
C#不仅支持方法覆盖,还支持方法隐藏。 简单地说,如果方法没有覆盖派生方法,它就会隐藏它。 必须使用new关键字声明隐藏方法。 因此,第二个清单中的正确类定义是:
using System; namespace Polymorphism { class A { public void Foo() { Console.WriteLine("A::Foo()"); } } class B : A { public new void Foo() { Console.WriteLine("B::Foo()"); } } class Test { static void Main(string[] args) { A a; B b; a = new A(); b = new B(); a.Foo(); // output --> "A::Foo()" b.Foo(); // output --> "B::Foo()" a = new B(); a.Foo(); // output --> "A::Foo()" } } }
我有时对新关键字使用的一个用法是在并行inheritance树中使用’穷人的属性协方差’。 考虑这个例子:
public interface IDependency { } public interface ConcreteDependency1 : IDependency { } public class Base { protected Base(IDependency dependency) { MyDependency = dependency; } protected IDependency MyDependency {get; private set;} } public class Derived1 : Base // Derived1 depends on ConcreteDependency1 { public Derived1(ConcreteDependency1 dependency) : base(dependency) {} // the new keyword allows to define a property in the derived class // that casts the base type to the correct concrete type private new ConcreteDependency1 MyDependency {get {return (ConcreteDependency1)base.MyDependency;}} }
inheritance树Derived1:Base对ConcreteDependency1:IDependency’具有’parallell依赖’。 在派生类中,我知道MyDependency的类型为ConcreteDependency1,因此我可以使用new关键字从基类隐藏属性getter。
编辑:请参阅Eric Lippert撰写的这篇博客文章,以获得对新关键字的详细解释。
我认为ArsenMkrt的例子并不完全正确,至少它没有完全解释隐藏function。 通过从B类中的Foo方法中删除new关键字,您仍然可以获得输出
A::Foo() B::Foo() A::Foo()
在像Java这样的编程语言中,所有方法都是“虚拟”的,你希望获得输出
A::Foo() B::Foo() B::Foo()
通过上面的ArsenMkrt代码,由于实例化
A a; B b; a = new A(); b = new B(); a.Foo(); b.Foo(); a = new B(); //<< Here a.Foo();
然而,在他的例子中,你仍然得到“A :: Foo()”,因为在C#方法中默认情况下不是虚拟的,因此方法B :: Foo()会自动隐藏A的Foo()。 要实现多态行为,必须按如下方式编写:
class A { public virtual void Foo() { Console.WriteLine("A::Foo()"); } } class B : A { public override void Foo() { Console.WriteLine("B::Foo()"); } }
现在是“new”关键字出现的地方。实际上,当你从B :: Foo()离开“覆盖”时,你再次隐藏A :: Foo()意味着你不会覆盖它的默认行为而你不实现多态,即你再次得到“A :: Foo()”作为输出。 同样可以实现 - 而这里我不是100%理解为什么你要把它放在 - 通过放置“new”关键字像..
class A { public virtual void Foo() { Console.WriteLine("A::Foo()"); } } class B : A { public new void Foo() { Console.WriteLine("B::Foo()"); } }
然后你再次获得输出
A::Foo() B::Foo() A::Foo()
一个稍微模糊的场景,其中方法隐藏是合适的,但由于缺乏任何干净的惯用方式来表达它,在基类将受保护的成员暴露给可inheritance的后代的情况下,但是后代知道没有任何方法进一步派生的类可以使用该成员而不会破坏事物。 许多类应该隐藏的方法的一个主要示例(但很少有)是MemberwiseClone()
。 在许多情况下,如果一个类有一个private
成员,它希望是对可变对象的唯一现有引用,那么派生类就没有可能正确地使用MemberwiseClone()
。
请注意,隐藏受保护成员不构成违反LSP的行为。 与LSP的一致性要求在代码可能期望引用基类对象但接收对派生类对象的引用的地方,后一个对象应该像基类对象一样工作。 但是,受保护的成员不在LSP的范围内,因为每个类型都绝对知道它的基类型。 如果Bar
和Boz
都来自Foo
,并且Boz
隐藏了Bar
所需的受保护成员, Boz
隐藏该成员的事实将不会影响Bar
,因为Bar
的基类型实例不可能是Boz
或其他任何其他比Foo
。 没有替代是可能的,因此可替代性是无关紧要的。
这可能有所帮助。
class Base { public void F() {} } class Derived: Base { public void F() {} // Warning, hiding an inherited name }
在上面的示例中,Derived中的F声明会导致报告警告。 隐藏inheritance的名称特别不是错误,因为这将排除基类的单独演变。 例如,上述情况可能是因为更高版本的Base引入了一个F方法,该方法在该类的早期版本中不存在。 如果上述情况是错误,那么对单独版本化的类库中的基类所做的任何更改都可能导致派生类变为无效。 资料来源: https : //msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx
有一次当你需要添加/修改基类方法上的属性时。 例如:
[Browsable(true)] [EditorBrowsable(EditorBrowsableState.Always)] public new event EventHandler TextChanged { add { base.TextChanged += value; } remove { base.TextChanged -= value; } }
基类Control
类有一个TextChanged
事件,但基本事件上有各种属性,以防止它出现在intellisense或设计器中。 因为我使用它的类广泛使用了Text
属性和TextChanged
事件,所以我希望TextChanged
事件在intellisense中显示并在属性窗口中可见。