关于c#:为什么难以访问的成员被认为是继承的?

Why are inaccessible members considered inherited?

C规范规定:

The declared accessibility of a base class member does not control
whether the member is inherited--inheritance extends to any member
that isn't an instance constructor,static constructor,or destructor.
However, an inherited member may not be accessible in a derived type,
either because of its declared accessibility or because it is hidden
by a declaration in the type itself.

为什么不可访问的成员被认为是继承的?为什么要这样区分?

作为一个具体的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
    const string foo ="c";

    internal void DoWork() { }
}

class B: A
{
    const string bar ="d";//renamed to foo does not appear to have a noticeable impact
    B() { bar = foo; }//inaccessible due to protection level

    internal new void DoWork() { }//hide inherited member
}

在我看来,在运行时继承意味着共享状态和/或行为。在foo的情况下,这种情况不会发生。

是否继承DoWork()的行为取决于B。因此,DoWork()作为B的成员是直观和相关的。另一方面,为什么foo被视为B的成员?B不能读写foo


在您的例子中,您所说的是const,它是隐式静态的。静态成员实际上不会被继承。刚刚检查了规范,这意味着静态成员是继承的——但是由于它们不代表状态,不能成为多态的一部分,所以它至少是一种"不同"的继承。我认为静态成员仅仅是对派生类"通过简单的名称可用",假设它们是完全可访问的——换句话说,它与名称解析有关,而不是真正的继承。

如果这是一个私有实例变量,那么它将是从A派生的任何类型实例的任何实例的状态的一部分,因此它将是继承状态。如果你考虑一个对象的状态和行为被继承,在我看来这是有意义的。

(可能有必要弄清楚你对静态部分还是私有部分感兴趣;它们有些正交。)


这篇文章可能对您有所帮助。

Inheritance and representation

Why is an inaccessible member considered inherited? Why is such a distinction made/practical?

最好问一个相反的问题:为什么制定一个规则说不可访问的成员不是继承的呢?让我们考虑一下这样一条规则的后果。

首先,如果你有

1
2
3
4
5
6
7
class B
{
  internal int x;
}
class D1 : B {}
// in another assembly
class D2 : B {}

你会说x是由d1继承的,而不是由d2继承的?这看起来很奇怪。或者这个案子怎么样:

1
2
3
4
5
6
class B
{
  private int x;
  private class D1 : B {}
}
class D2 : B {}

同样,你会说x是由d1继承的,而不是由d2继承的?

在每一种情况下,派生类都有一个整型字段x,但您会仅仅基于在某些源代码位置中不能通过名称访问该字段而否认这一事实吗?把"继承"的定义与"可访问"的定义联系起来,有什么令人信服的价值呢?

简单地使这两个概念正交就容易多了。""继承的"表示"基类型的此成员也是派生类型的成员"。可访问性是指访问源代码是否在声明成员的可访问性域内。他们之间没有什么关系,所以我们不要不必要地把他们混为一谈。


通过演示最容易解释这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Parent
{
    private int value;
    public virtual int GetValue()
    {
        return value;
    }
}

public class Child : Parent
{
    public int GetOtherValue()
    {
        //"value" is no accessible in this scope
        return GetValue() + 1;
    }
}

创建对象时,会为该类型的所有实例字段分配内存。Child实际上有一个实例字段,而不是0。value继承自Parent,是Child的一个实例字段。当您创建一个Child实例时,它对value有自己的价值。value字段在Child的定义中不可访问(因为它是私有的);它只能通过Parent公开的可访问的方法/属性访问。