讨论:
在C#中类的成员可以通过private等关键词限制访问权限,众所周知,具有private关键字的属性和方法无法被其它类访问。
例如以下代码:
// 示例1
class A
{
private int x;
public int y;
}
class B
{
public void Func(A a)
{
a.x = 1; // 不通过,无法访问a的私有成员
a.y = 1; // 通过,可以访问a的公共成员
}
}
在B的Func中,只能访问a.y,而不能访问a.x,这是因为private关键字限制了x只能被类A访问
然而 ,注意我说的是,只能被类A访问,而不是只能被类A的实例a访问,来看以下例子:
// 示例2
class A
{
private int x;
public int y;
public void Func(A a)
{
a.x = this.x; // 通过
a.y = this.y; // 通过
}
}
在这个例子中,同样是通过a.x,对类A的a实例的私有成员x进行了访问(有点拗口),但是却能编译通过的。
这一点让人感到奇怪,因为通常来说,如果x是某个类的私有属性,我们一般不会写下类似a.x的访问语句,因为这通常是不通过的,然而在示例2中,这种访问却是符合语法的,起码编译器是不会报错的。
这似乎说明了一个特性,那就是在C#中,类A的a实例可以访问类A的b实例的私有成员
结论
经过多种试验,查阅相关资料,验证了这个特性:C#的访问权限设计,是基于类的,而不是基于实例的。一个类的实例可以访问该类的任何其他实例的私有成员。
这种特性看起来有一点破坏了面向对象的封装性,在设计时容易产生一些意外,比如在涉及到派生类的时候。
不过这种特性也使得C#在实现某些功能时提供更大的灵活性,比如复制构造函数、比较函数等,它们需要访问另一个实例的私有数据。
作为开发者在使用这种权限时需要谨慎,在设计面向对象系统时避免破坏封装性。
其他语言
C++
我在C++上进行了测试,发现C++也具有相同的特性,在以下例子中,FuncA可以访问a.x,而FuncB无法访问a.x:
class A
{
private:
int x = 1;
public:
void FuncA(A a)
{
a.x = 2;
}
};
class B
{
public:
void FuncB(A a)
{
a.x = 2;
}
};
JAVA
我对JAVA了解得不多,曾经与同事讨论发现,JAVA与C#在语法上至少有80%的相似度,一些简单的代码甚至只要换个壳子就可以互相运行。但是与同事就访问控制的特性讨论后发现,JAVA对于访问权限的控制却是更加严格,在Java中,一个类的实例无法访问另一个实例的私有成员,访问权限是基于实例的。这一点与C#便有区别
后记
关于C#的访问控制,我也是偶然才发现它基于类而不是基于实例这一特性的,这在后续的程序设计中是值得注意的一点,因此写下这篇文章以作记录。