代码之家  ›  专栏  ›  技术社区  ›  vijaysylvester

方法隐藏在C_中,并使用有效的示例。为什么要在框架中实现?现实世界的优势是什么?

  •  14
  • vijaysylvester  · 技术社区  · 16 年前

    有人能解释一下 方法隐藏 在C中,有一个有效的例子吗?

    如果方法是使用 new 派生类中的关键字,则不能重写它。然后用不同的名称创建一个新方法(基类中提到的方法除外)。

    有什么特别的理由使用 新的 关键字?

    6 回复  |  直到 10 年前
        1
  •  7
  •   Arsen Mkrtchyan    16 年前

    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()"
                }
            }
        }
    
        2
  •  10
  •   jeroenh    16 年前

    对于这个新的关键字,我有时会用到并行继承树中的“穷人属性协方差”。考虑这个例子:

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

    派生的继承树1:Base对ConcreteDependency1:Idependency具有“Parallel Dependency”。在派生类中,我知道MyDependency的类型为ConcreteDependency1,因此可以使用new关键字将属性getter隐藏在基类中。

    编辑:参见 this blog post by Eric Lippert 为了更好地解释这个新关键字。

        3
  •  7
  •   Juri    16 年前

    我认为arsenmkrt的例子不完全正确,至少它没有完全解释隐藏特性。通过从类B中的foo方法中删除新的关键字,仍然可以得到输出

    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”关键字出现的地方。实际上,当您将“override”从b::foo()中去掉时,您会再次隐藏a::foo(),这意味着您不会重写它的默认行为,也不会实现多态性,即您会再次得到“a::foo()”作为输出。同样的情况也可以实现——这里我不完全理解你为什么要把它放在这里——通过放置“new”关键字,比如……

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

    你又得到了输出

    A:()
    B::()
    A:()
    
        4
  •  1
  •   supercat    12 年前

    一个稍显模糊的场景是,如果方法隐藏是适当的,但没有任何干净的惯用表达方法,则是在基类将受保护成员暴露给可继承的后代的情况下,但该后代知道,任何其他派生类都无法在不破坏事物的情况下使用该成员。许多类应该隐藏(但很少隐藏)的方法的主要示例是 MemberwiseClone() . 在许多情况下,如果一个类 private 成员应是对可变对象的唯一现有引用,派生类无法使用任何可能的方法 成员WiseClone() 正确地。

    注意,隐藏受保护成员 构成对LSP的违反。与LSP的一致性要求,在代码可能期望引用基类对象但接收到对派生类对象的引用的地方,后者应该像基类对象一样工作。但是,受保护的成员不在LSP的范围内,因为每个类型都绝对知道其基类型。如果 Bar Boz 两者都源自 Foo 博兹 隐藏受保护的成员 酒吧 需要,事实是 博兹 隐藏成员不会影响 酒吧 ,因为 酒吧 的基类型实例不能是 博兹 或者其他的 . 不可能有替代,因此替代性是不相关的。

        5
  •  0
  •   Uneverno    10 年前

    这可能会有所帮助。

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

    在上述示例中,派生中的f声明会导致报告警告。隐藏继承的名称并不是一个错误,因为这会阻止基类的独立演化。例如,上述情况可能是因为更高版本的Base引入了一个F方法,而该方法在早期版本的类中不存在。如果上述情况是一个错误,那么对单独版本化类库中的基类所做的任何更改都可能导致派生类失效。 来源: https://msdn.microsoft.com/en-us/library/aa691135%28v=vs.71%29.aspx

        6
  •  0
  •   Newell Clark    10 年前

    有一次,当您需要添加/修改基类方法上的属性时,您将使用它们。例如:

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

    底座 Control 类有 TextChanged 事件,但基事件具有各种属性,以防止它在IntelliSense或设计器中显示。因为我在中使用的类广泛使用了 Text 财产和 事件 活动,我想要 事件 事件以IntelliSense显示并在“属性”窗口中可见。