C# 为什么要屏蔽基类成员?

C# 为什么要屏蔽基类成员?,c#,class,encapsulation,mask,C#,Class,Encapsulation,Mask,我刚刚学习了如何屏蔽基类成员(使用new),但是我没有理解为什么我要这么做。掩蔽是否像使用封装一样为我们提供了一定程度的保护?请告知。它不仅仅用于掩蔽。它实际上打破了继承链,因此如果调用基类方法,则不会调用派生类中的方法(仅调用基类中的方法) 实际上,您正在创建一个与基类方法无关的新的方法。因此出现了“新”关键字 请记住,如果您想定义一个与基类型方法具有相同签名但返回类型不同的方法,可以使用“new”关键字。您很少使用“new”来屏蔽基类成员 它主要用于派生类首先拥有成员,然后将其添加到基类中的

我刚刚学习了如何屏蔽基类成员(使用new),但是我没有理解为什么我要这么做。掩蔽是否像使用封装一样为我们提供了一定程度的保护?请告知。

它不仅仅用于掩蔽。它实际上打破了继承链,因此如果调用基类方法,则不会调用派生类中的方法(仅调用基类中的方法)

实际上,您正在创建一个与基类方法无关的新的方法。因此出现了“新”关键字

请记住,如果您想定义一个与基类型方法具有相同签名但返回类型不同的方法,可以使用“new”关键字。

您很少使用“new”来屏蔽基类成员

它主要用于派生类首先拥有成员,然后将其添加到基类中的情况——相同的名称用于不同的目的。
新的
就是要你承认你知道你正在以不同的方式使用它。当C++中添加基成员时,它只是默默地将现有方法合并到继承链中。在C#中,您必须在
new
override
之间进行选择,以显示您知道发生了什么。

我遇到的唯一有效的安全示例是更具体地使用返回类型或在属性上提供设置访问器。我并不是说只有这些,但这就是我所发现的

例如,假设您有一个非常简单的底座,如下所示:

public abstract class Base
{
  public string Name { get; protected set; }

  public Base(string name)
  { Name = name; }
}
public class Derived : Base
{
  public new string Name 
  {
    get { return base.Name; }
    set { base.Name = value; }
  }

  public Derived(string name) : base(name)
  { }         
}
您可以有一个更像这样的派生:

public abstract class Base
{
  public string Name { get; protected set; }

  public Base(string name)
  { Name = name; }
}
public class Derived : Base
{
  public new string Name 
  {
    get { return base.Name; }
    set { base.Name = value; }
  }

  public Derived(string name) : base(name)
  { }         
}
假设业务规则允许这个特定的派生具有可变名称,我相信这是可以接受的。
new
的问题在于,它会根据实例被视为什么类型而改变行为。例如,如果我说:

Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.
如果我可以
Base
类上设置Child
,我可能会在
派生的
类中遇到铸造问题。另一个例子:

Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child;  // c is of type Base
var e = d.Child;  // e is of type Derived

我不能通过将所有
派生的
类作为基础来破坏任何业务规则,只需不进行类型检查和强制转换即可。

这实际上被称为成员隐藏。有几个常见的场景可以适当地使用它

  • 它允许您解决基类或派生类作者无意中创建与现有标识符冲突的成员名称的版本控制问题
  • 它可用于模拟返回类型的协方差
关于第一点……基类的作者可能会在以后添加与派生类中现有成员同名的成员。基类作者可能不了解派生类,因此不希望她能够避免名称冲突。C#支持使用隐藏机制独立演化类层次结构

关于第二点……您可能希望一个类实现一个指定某个方法签名的接口,因此您被锁定为只返回某个类型的实例,而同时您已经对该类型进行了子类化,并且希望调用方看到具体的类型。考虑这个例子。

public interface IFoo { }

public class ConcreteFoo { }

public abstract class Base
{
  private IFoo m_Foo;

  public Base(IFoo x) { m_Foo = x; }

  public IFoo Foo { get { return m_Foo; } }
}

public class Derived
{
  public Derived(ConcreteFoo x) : base(x) { }

  public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}

你指的是所谓的。这主要是一个方便的功能。如果使用
new
从一个不控制源代码的类继承,将允许您更改方法的行为,即使该方法未声明为虚拟(或者如果它是虚拟的,则完全更改签名)。
new
关键字只会抑制编译器警告。您基本上是在通知编译器,您是有意对父类隐藏该方法

出于同样的原因,Delphi重新引入了
关键字

除了被抑制的警告,这还能给你带来什么?不是很多。无法从父类访问
new
方法。如果子类直接实现该接口(与从其父类继承该接口类似),则可以从接口访问该接口。您仍然可以从子类调用父类的成员。类的任何其他后代都将继承
新成员,而不是父类中的成员

我刚刚学习了如何屏蔽基类成员(使用new)

仅供参考,此功能通常称为“隐藏”,而不是“掩蔽”。我认为“掩蔽”是在位数组中清除位

我不明白我为什么要那样做

通常你不想。出于使用和不使用此功能的某些原因,请参阅我2008年关于此主题的文章:

掩蔽是否像使用封装一样为我们提供了一定程度的保护


不,它没有。

我不确定我是否理解这个问题,您能否举例说明掩蔽基类成员的含义。尽管派生类不能删除它继承的任何成员,但它可以隐藏它们。1.要隐藏继承的成员,请声明具有相同类型和名称的新成员。2.还可以隐藏静态成员。隐藏的好处是什么?但这并不能解释你为什么要这么做。(也就是说,您所做的就是告诉我们您编写的函数是如何不被调用的——如果它没有被调用,那有什么意义呢?)为什么?如果不希望新方法成为具有相同名称和参数类型的虚拟方法的同一继承链的一部分。作为一个副作用,它允许您重新声明具有相同签名的方法,但返回类型除外。只要你记住,当你调用基类型的方法时,它不会被调用。你的“作为副作用”句子回答了这个问题。剩下的工作可以通过以下两种方式更好地完成:a)给方法起一个不同的名字,或者b)不写任何东西