method hiding in c# with a valid example. why is it implemented in the framework? what is the Real world advantage?

一世执手 提交于 2020-01-27 02:23:46

问题


Can anyone explain the actual use of method hiding in C# with a valid example ?

If the method is defined using the new keyword in the derived class, then it cannot be overridden. Then it is the same as creating a fresh method (other than the one mentioned in the base class) with a different name.

Is there any specific reason to use the new keyword?


回答1:


C# not only supports method overriding, but also method hiding. Simply put, if a method is not overriding the derived method, it is hiding it. A hiding method has to be declared using the new keyword. The correct class definition in the second listing is thus:

    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()"
            }
        }
    }



回答2:


One use I sometimes have for the new keyword is for 'poor mans property covariance' in a parallell inheritance tree. Consider this example:

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;}}
}

The inheritance tree Derived1 : Base has a 'parallell dependency' on ConcreteDependency1 : IDependency'. In the derived class, I know that MyDependency is of type ConcreteDependency1, therefore I can hide the property getter from the base class using the new keyword.

EDIT: see also this blog post by Eric Lippert for a good explanation of the new keyword.




回答3:


I think ArsenMkrt's example is not fully correct, at least it does not fully explain the hiding feature. By dropping the new keyword from the Foo method in class B, you will still get the output

A::Foo()
B::Foo()
A::Foo()

In a programming language like Java, where all methods are "virtual", you'd expect to get the output

A::Foo()
B::Foo()
B::Foo()

by taking ArsenMkrt's code above, due to the instantiation

A a;
B b;

a = new A();
b = new B();
a.Foo(); 
b.Foo(); 

a = new B(); //<< Here
a.Foo();  

In his example however, you still get "A::Foo()" because in C# methods aren't virtual by default and so the method B::Foo() automatically hides A's Foo(). To achieve the polymorphic behavior one has to write it as follows instead:

class A
{
    public virtual void Foo() { Console.WriteLine("A::Foo()"); }
}

class B : A
{
    public override void Foo() { Console.WriteLine("B::Foo()"); }
}

Now is where the "new" keyword comes in. Actually when you leave the "override" from B::Foo(), then you again would hide A::Foo() meaning that you don't override it's default behavior and you don't achieve polymorphism, i.e. you get "A::Foo()" again as output. The same can be achieved - and here's where I don't 100% understand why you HAVE to put it - by placing the "new" keyword like..

class A
{
    public virtual void Foo() { Console.WriteLine("A::Foo()"); }
}

class B : A
{
    public new void Foo() { Console.WriteLine("B::Foo()"); }
}

and you again get the output

A::Foo()
B::Foo()
A::Foo()



回答4:


One slightly obscure scenario where method hiding would be appropriate, but for a lack of any clean idiomatic way of expressing it, is in circumstances where a base class exposes a protected member to an inheritable descendant, but that descendant knows that there is no way any further derived classes could use that member without breaking things. A prime example of a method which many classes should hide (but very few do) is MemberwiseClone(). In many cases, if a class has a private member which expects to be the only extant reference to a mutable object, there is no possible means by which a derived class could ever use MemberwiseClone() correctly.

Note that hiding of protected members does not constitute a violation of the LSP. Conformance with the LSP requires that in places where code might be expecting reference to a base-class object but receives a reference to a derived-class object, the latter object should work as would the base-class one. Protected members, however, are outside the scope of the LSP, since every type knows its base type absolutely. If Bar and Boz both derive from Foo, and Boz hides a protected member that Bar requires, the fact that Boz hides the member won't affect Bar, because Bar's base-type instance can't possibly be a Boz or anything other than Foo. No substitution is possible, and hence substitutability is irrelevant.




回答5:


This might help.

class Base
{
   public void F() {}
}
class Derived: Base
{
   public void F() {}      // Warning, hiding an inherited name
}

In the above example, the declaration of F in Derived causes a warning to be reported. Hiding an inherited name is specifically not an error, since that would preclude separate evolution of base classes. For example, the above situation might have come about because a later version of Base introduced an F method that wasn't present in an earlier version of the class. Had the above situation been an error, then any change made to a base class in a separately versioned class library could potentially cause derived classes to become invalid. Source: https://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx




回答6:


One time when you would use them is when you need to add/modify an attribute that is on a base-class method. For example:

[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged
{
    add { base.TextChanged += value; }
    remove { base.TextChanged -= value; }
}

The base Control class has a TextChanged event, but the base event has all kinds of attributes slapped on it to prevent it from showing up in intellisense or the designer. Because the class I used that in makes extensive use of both the Text property and the TextChanged event, I wanted the TextChanged event to show up in intellisense and be visible in the properties window.



来源:https://stackoverflow.com/questions/1193848/method-hiding-in-c-sharp-with-a-valid-example-why-is-it-implemented-in-the-fram

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!