面对对象中很重要的一个概念就是封装
诸如public,private之类的访问修饰符
本文就提供了一些有关于这些访问修饰如何实现的具体信息

 


因为.net实现了类型的机器可读,因此其提供了丰富的访问权限控制
注意:本文中访问权限控制特指类和类成员的访问,与其他高级安全特性无关

c#的访问修饰是这种权限控制的一个子集

在编程中,需要用访问修饰符来指定其访问权限

目前 C# 支持使用以下访问修饰符之一来指定其可访问性

public
     同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。
private
     只有同一类或结构中的代码可以访问该类型或成员。
protected
    只有同一类或结构或者派生类中的代码可以访问该类型或成员。
internal
    同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。
protected internal
     同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。

注意: C#语言只实现了.net访问权限控制的一个子集,例如CLR提供了名为 Family Assembly 的访问权限控制,仅可以被所定义的类型(或者其任何嵌套类型),及与其在同一个程序集中派生类型访问  ,而C#语言并不支持这种访问权限控制(VB.NET 也不支持)

以上是概括,如果你还想知道更多,下面将会尝试着说明,.CLR是如何使这种自由,灵活的访问控制成为可能
继续阅读,需要一些c++以及面对对象的知识,我的一篇博客,略微提及了这些内容 

http://blog.csdn.net/only_lonely/archive/2010/03/11/5370787.aspx

 

1,对象只是编译器的把戏 public,private与protect

  当各种软件开发方法,思想甚嚣尘上之时,许多人容易忽略一个基本的事实,CPU并不理解对象,类,继承,多态等等这些纷繁的东西,它唯一能够明白的,只是一串串二进制的流.之所以能够出现那么多的概念,只是因为有人换了一种方法讲述故事
   可以把一个类分成两半,一半是只会在内存中存在一份拷贝的成员(静态的字段静态或者非静态的方法等) 选择这么做的原因很简单,因为他们只需要一份
   另一半是会在内存中存在多份拷贝成员(非静态的字段) 选择这么做的原因很无奈,因为如果不这么做,就无法产生类的多个实例
   如下的一个类(C++)
  class A
   {
       private  void a() //  假设在虚拟内存中的地址为: 0000FFFF
       {};
   };

  当编译器编译这样一个类,会把函数a放在起始地址为 0000FFFF 的虚拟内存段上
  以后只要遇见了a的函数调用,它就会检察是否是A类内的成员调用它,如果不是,产生一个错误,如果是编译器就会产生 call 0000FFFF 的汇编指令 (汇编指令会因计算机的CPU体系不同而有所区别,但大意如此)
  你有发现什么问题吗? 经过编译器的转换,类不见了,实例也不见了,有的只是一个简单的汇编指令,如果你在你的代码中,嵌入一段汇编代码
  class B
  {
       public void b()
       {
             __asm
             {
                   call 0X0000FFFF; //杯具发生现场
             }
       }
  };
 在理想的情况下,编译器会觉得这样做并不好,会给我们一个错误的提示,可是事实是残酷的,它不会有任何错误的提示,而你轻易的突破了private的访问权限控制

事实真的是如此吗?让我们来做一个实验,(vs2005 release , win7 X86 32位下编译通过)

#include<conio.h>
#include<iostream>
using namespace std;


class C
{
public:
      C(int value)
      {
          this->m_Value = value ;
      }
      int GetValue()
      {
          return  this->m_Value;
      }
private:
    int m_Value;
};

void D( C* ptr)
{
   
    int * value = (int *)(ptr);
                *value = 123;
}

int main()
{
       C * c = new C(0);
       D(c);
       cout << (c->GetValue()) << endl;
      _getch();
}
输出结果为 : 123 ;

如果看不明白,只看main函数就行了,给c的变量m_Value初始化为0,却在类的外部被改变,private权限被突破

由上可知,所谓的public, protected,private只不过是编译器做的把戏,

那么在c#中,public,protected,private又是如何实现的呢?
其实它的实现,与c++编译做的有些类似,只不过在它生成安全代码的时候,是不允许指针操作的,而且进行类型强制转换的时候,会有检查,不兼容的根本过不了检查关
如果你十分想自己试一试突破它的private防御,可以使用unsafe语句块,我在上面提及的博客里,会有一些提示(具体能否实现,我没做过实验)
还有另一种方法,就是利用反射(这个是肯定能成功的,就是要了解的概念,多了些 :-))

2.把类存放在硬盘上, internal 与 protected internal
 学过c++的童鞋会知道.c++的访问标识符里,只有 public, private和 protected,并没有提供  internal  与  protected internal
 为什么?
 因为它要保持简洁,单纯
 c++是一门能让你看清真像的语言,没有那许多复杂的遮盖物
 在c++中,所有的类,类中的方法调用,类的多态,全部被编译成汇编代码,安静的存放在硬盘上
 也就是说,当你拿起一份由c++编译成的exe文件,你看到的,只是一个又一个的汇编代码,你无法(或者很难)把汇编代码反推得到当初编译它时类的信息
 据说,某天,一个熟透了的苹果砸在了.net设计人员的头上,他灵机一动 "为什么不在exe文件的某个角落里,写下 诸如 '当初编译它的时候,它是个类,有XX个方法,XX个字段,和它在一起的有XXX'的信息呢?"
 接下来的事,大家都知道了,C#诞生了

注意:上述描述,一定程度上颠倒了框架(设计,约定)与语言实现之间的位置,同一个框架,体系可以由不同的语言去实现 .net上,你可以用VB.NET,和 C#,同一种语言,可以在不同的框架体系上生存 c++ 能在MFC上活的happy,在QT上日子也过的很滋润.

因为在运行的时候,我能知道这是一个类,和它在一个程序集的有谁,正是因为知道了这些,才能实现internal, protected internal

友情提示 : 实现有多种, 标准只唯一,除了实在好奇难耐,请舍实现而取标准