这种继承语义的名称

时间:2011-01-19 04:41:56

标签: c# inheritance

public class _base 
{ 
    protected int x = 5;
    protected int GetX(_base b) { return b.x; }
}


public class _derived : _base 
{ 
    public int Foo()
    {
        var b = new _base();
        //return b.x;  // <-- this would be illegal
        return GetX(b); // <-- This works and does exactly the same as the line above
    }
}

(请不要更改代码。它正在运行并显示问题。)

错误是

Cannot access protected member '_base.x' via a qualifier of type '_base'; the qualifier must be of type '_derived' (or derived from it)

请注意,因为b的类型为_base而我们不在基础中,所以我们无法访问受保护的成员。我想是因为_base可能是其他派生类型,因此它不保护代码,但这不是重点。我正在做的是使用额外的受保护方法为上述问题创建一个解决方法。这给了我想要的行为和我想要的保护。我希望有一个关键字允许这种访问,但没有。我感兴趣的是这个“模式”是否有名称。

(我使用受保护,因为内部允许同一个程序集访问的任何人)

4 个答案:

答案 0 :(得分:3)

通常不允许这种访问,因为访问修饰符适用于类(作为元访问属性)。在派生类中,基类的实例与派生类没有类关系。这里我们混合实例和类。 protected关键字仅提供对派生类的访问,但是来自任何实例(即使在派生类中)。

这显然是语言的缺陷,但由于99.9%的时间没有使用它,因此不需要它。在任何情况下,C#中都没有提供您想要的关键字。

答案 1 :(得分:2)

更新:重写此答案,因为问题已被重写。

我不知道你所说明的模式的任何名称。

正如您猜想的那样,访问该字段是非法的原因是因为我们不知道实例b是_derived的实例。 “受保护”访问意味着_derived只允许访问 _deeded 实例的受保护成员;不允许访问也是从_base派生的“SomeOtherType”实例的受保护成员。

现在,如果问题确实是“有没有办法通过任何每个派生类中直接访问成员x实例吗?”好的。你拒绝将其作为内部的明显解决方案。 (*)还有另一种方式。这样做:

abstract class B
{
    private B() {}
    private int x;
    private class D1 : B { }
    private class D2 : B { }
    public static B MakeD1() { return new D1(); } 
    public static B MakeD2() { return new D2(); }
}

现在B的方法和派生类D1和D2的方法都能够直接访问this.x,但没有其他类型的方法能够这样做。除D1和D2之外,没有其他派生类型;不可能因为B的唯一构造函数是私有的。并且不存在任何不是D1或D2的B实例,因为它是抽象的。


(*)请记住,如果您将其设为内部版本,那么您唯一需要担心访问其成员的人就是您的同事。如果他们对会员做了一些虐待,那么在代码审查中对他们进行抨击是一个完全可以接受的解决方案。

答案 2 :(得分:0)

封装

http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming

基本上,您可以通过访问者(“设置者”和“获取者”)控制谁有权访问成员。基础数据的布局方式对用户来说仍然是隐藏的。

想一想:

如果您想在基类中重命名X变量(无论出于何种原因),但是存在100个派生自该基类的类,它们直接访问它。

你会打破这段代码。

class derived
{
  void DoSomething() { x += 1; } // x renamed, doesn't compile anymore
}

现在,通过封装,由于x无法直接访问,我们获得了访问者:

class derived
{
  void DoSomething() { SetX(GetX() + 1); } // No prob!
}

答案 3 :(得分:0)

我想我明白你的意思。不要在方法中创建基类的实例。它由构造函数创建。引用基类成员只使用成员名称,或者您使用base关键字在其前面加上

在上面的示例中,您将按如下方式使用它:

class A : _base { 
     void Foo() {
         x = 10; //or base.x = 10;
         SetX(10); //or base.SetX(10);
         Console.WriteLine(GetX()); //or base.GetX()
     }
}

此外,您可能对Properties构造感兴趣,这对于java丑陋的getX和setX模式来说是一个很好的语法糖。