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可能是其他派生类型,因此它不保护代码,但这不是重点。我正在做的是使用额外的受保护方法为上述问题创建一个解决方法。这给了我想要的行为和我想要的保护。我希望有一个关键字允许这种访问,但没有。我感兴趣的是这个“模式”是否有名称。
(我使用受保护,因为内部允许同一个程序集访问的任何人)
答案 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模式来说是一个很好的语法糖。