深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

时间:2022-09-06 14:26:08

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类、类成员函数、类成员变量进行访问控制。同时,访问控制符也是语法保留关键字,用于封装组件。

Public, Private, Protected at Class Level

在创建类时,我们需要考虑类的作用域范围,如谁可访问该类,谁可访问该类成员变量,谁可访问该类成员函数。 换而言之,我们需要约束类成员的访问范围。一个简单的规则,类成员函数、类成员变量之间可以*

访问不受约束,这里主要说的是外部的访问约束。在创建class的时候,默认的访问控制符为private。

下面做个小实验,打开Visual Studio,创建一个C#的Console应用,命名为AccessModifiers。 添加一个类,命名为Modifiers ,拷贝如下代码:

  1: using System;
  2:
  3: namespace AccessModifiers
  4: {
  5:     class Modifiers
  6:     {
  7:         static void AAA()
  8:         {
  9:             Console.WriteLine("Modifiers AAA");
 10:         }
 11:
 12:         public static void BBB()
 13:         {
 14:             Console.WriteLine("Modifiers BBB");
 15:             AAA();
 16:         }
 17:     }
 18:
 19:      class Program
 20:     {
 21:         static void Main(string[] args)
 22:         {
 23:             Modifiers.BBB();
 24:         }
 25:     }
 26:    }

上面的代码创建了一个类Modifiers,它有2个static函数:AAA、BBB。其中BBB是public访问修饰符,在Main中调用BBB结果如下:

Modifiers BBB

Modifiers AAA

BBB被标记为public,既任何函数皆可访问和运行。AAA被标记为private,既AAA仅能被其类内函数访问,外包是无法访问的。

修改代码如下:

  1: class Program
  2:     {
  3:         static void Main(string[] args)
  4:         {
  5:             Modifiers.AAA();
  6:             Console.ReadKey();
  7:         }
  8:     }

则运行报错:

'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level

Modifiers

下面我们对AAA进行重构,修改如下:

  1: class Modifiers
  2:     {
  3:         protected static void AAA()
  4:         {
  5:             Console.WriteLine("Modifiers AAA");
  6:         }
  7:
  8:         public static void BBB()
  9:         {
 10:             Console.WriteLine("Modifiers BBB");
 11:             AAA();
 12:         }
 13:     }
 14:
 15:     class Program
 16:     {
 17:         static void Main(string[] args)
 18:         {
 19:             Modifiers.AAA();
 20:             Console.ReadKey();
 21:         }
 22:     }

运行结果:

'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level

既,protected修饰符的成员变量,仅能被其同类、子类访问,外部无法访问。

继承修改

我们接着添加子类,来扩展这个实例:

  1: class ModifiersBase
  2:     {
  3:         static void AAA()
  4:         {
  5:             Console.WriteLine("ModifiersBase AAA");
  6:         }
  7:         public static void BBB()
  8:         {
  9:             Console.WriteLine("ModifiersBase BBB");
 10:         }
 11:         protected static void CCC()
 12:         {
 13:             Console.WriteLine("ModifiersBase CCC");
 14:         }
 15:     }
 16:
 17:   class ModifiersDerived:ModifiersBase
 18:     {
 19:         public static void XXX()
 20:         {
 21:             AAA();
 22:             BBB();
 23:             CCC();
 24:         }
 25:     }
 26:
 27:  class Program
 28:     {
 29:         static void Main(string[] args)
 30:         {
 31:             ModifiersDerived.XXX();
 32:             Console.ReadKey();
 33:         }
 34:     }

运行结果:

'AccessModifiers.ModifiersBase.AAA()' is inaccessible due to its protection level

原因是AAA默认为Private访问控制符,仅可在基类中访问,子类无法访问。

类级别的Internal 修饰符

换另外一个场景,用Visual Studio新建一个dll类库AccessModifiersLibrary,添加一个ClassA类,标记为iternal修饰符,代码如下:

  1: AccessModifiersLibrary.ClassA:
  2:
  3: namespace AccessModifiersLibrary
  4: {
  5:     internal class ClassA
  6:     {
  7:     }
  8: }

编译后,会在~\AccessModifiersLibrary\bin\Debug下找到这个dll。 在Program.cs使用这个dll, 添加dll引用,添加命名空间:

  1: using AccessModifiersLibrary;
  2:
  3: namespace AccessModifiers
  4: {
  5:     class Program
  6:     {
  7:         static void Main(string[] args)
  8:         {
  9:             ClassA classA;
 10:         }
 11:     }
 12: }

编译代码,运行结果如下:

Compile time error: 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level

之所以报错,是因为internal 修饰符的作用域。internal 修饰符仅对当前程序集(dll 或 exe)内有效,因此,当class添加internal修饰符则意味着程序集外无法访问。

命名空间的修饰符

我们尝试给命名空间添加修饰符,代码如下:

  1: public namespace AccessModifiers
  2: {
  3:     class Program
  4:     {
  5:         static void Main(string[] args)
  6:         {
  7:
  8:         }
  9:     }
 10: }

运行报错。

Compile time error: A namespace declaration cannot have modifiers or attributes

结论,我们无法对命名空间添加修饰符,命名空间默认是public的作用域。

私有类

修改如下代码:

  1:  namespace AccessModifiers
  2: {
  3:     private class Program
  4:     {
  5:         static void Main(string[] args)
  6:         {
  7:
  8:         }
  9:     }
 10: }

编译报错:

Compile time error: Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal

类可被修饰为public、internal,它无法被标记为protected或者private。类默认的修饰符为internal。

重构代码如下:

  1:  namespace AccessModifiers
  2: {
  3:     public class Program
  4:     {
  5:         static void Main(string[] args)
  6:         {
  7:         }
  8:
  9:         public private void Method1()
 10:         {
 11:
 12:         }
 13:     }
 14: }

编译运行:

Compile time error: More than one protection modifier

结论,修饰符不支持嵌套。既每次仅能用一个修饰符。

Internal 类和Public成员函数

重构代码:

  1: namespace AccessModifiersLibrary
  2: {
  3:     internal class ClassA
  4:     {
  5:         public void MethodClassA(){}
  6:     }
  7: }
  8:
  9: using AccessModifiersLibrary;
 10:
 11:  namespace AccessModifiers
 12: {
 13:     public class Program
 14:     {
 15:         public static void Main(string[] args)
 16:         {
 17:             ClassA classA = new ClassA();
 18:             classA.MethodClassA();
 19:         }
 20:     }
 21: }

运行结果:

'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level The type 'AccessModifiersLibrary.ClassA' has no constructors defined 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level 'AccessModifiersLibrary.ClassA' does not contain a definition for 'MethodClassA' and no extension method 'MethodClassA' accepting a first argument of type 'AccessModifiersLibrary.ClassA' could be found (are you missing a using directive or an assembly reference?)

结论,类成员变量的访问控制受限于其类的修饰符,如上面例子class为internal修饰符,则该类仅能在程序集内可被访问。

Protected Internal

对代码进行重构,在ClassA、ClassB、ClassC中添加如下代码:

  1: namespace AccessModifiersLibrary
  2: {
  3:     public class ClassA
  4:     {
  5:         protected internal void MethodClassA()
  6:         {
  7:
  8:         }
  9:     }
 10:
 11:     public class ClassB:ClassA
 12:     {
 13:         protected internal void MethodClassB()
 14:         {
 15:             MethodClassA();
 16:         }
 17:     }
 18:
 19:     public class ClassC
 20:     {
 21:         public void MethodClassC()
 22:         {
 23:             ClassA classA=new ClassA();
 24:             classA.MethodClassA();
 25:         }
 26:     }
 27: }
 28:
 29: using AccessModifiersLibrary;
 30:
 31:  namespace AccessModifiers
 32: {
 33:     public class Program
 34:     {
 35:         public static void Main(string[] args)
 36:         {
 37:             ClassC classC=new ClassC();
 38:             classC.MethodClassC();
 39:         }
 40:     }
 41: }

运行结果无错误。

结论:Protected internal 修饰符做了2件事情,protected约定类类和继承类访问控制,internal约定了只能在当前程序集中。

Protected 类成员变量

  1: namespace AccessModifiers
  2: {
  3:     class AAA
  4:     {
  5:         protected int a;
  6:         void MethodAAA(AAA aaa,BBB bbb)
  7:         {
  8:             aaa.a = 100;
  9:             bbb.a = 200;
 10:         }
 11:     }
 12:      class BBB:AAA
 13:      {
 14:          void MethodBBB(AAA aaa, BBB bbb)
 15:          {
 16:              aaa.a = 100;
 17:              bbb.a = 200;
 18:          }
 19:      }
 20:     public class Program
 21:     {
 22:         public static void Main(string[] args)
 23:         {
 24:         }
 25:     }
 26: }

编译结果:

Cannot access protected member 'AccessModifiers.AAA.a' via a qualifier of type 'AccessModifiers.AAA'; the qualifier must be of type 'AccessModifiers.BBB' (or derived from it)

结论:AAA中定义了一个a的protected变量,其仅能在自己内部访问和继承其的子类内访问。但是,通过传参方式传入的则无法访问--这里要求是public权限。

继承中访问优先级

看代码:

  1:  namespace AccessModifiers
  2: {
  3:     class AAA
  4:     {
  5:
  6:     }
  7:     public class BBB:AAA
  8:      {
  9:
 10:      }
 11:     public class Program
 12:     {
 13:         public static void Main(string[] args)
 14:         {
 15:         }
 16:     }
 17: }

编译报错:

Compile time error: Inconsistent accessibility: base class 'AccessModifiers.AAA' is less accessible than class 'AccessModifiers.BBB'

子类不能比其基类的访问控制符作用域范围大,如上面的例子中,基类为internal,而子类为public则报错了。

去掉继承,代码重构为如下结果:

  1:  namespace AccessModifiers
  2: {
  3:     class AAA
  4:     {
  5:
  6:     }
  7:     public class BBB
  8:      {
  9:         public AAA MethodB()
 10:         {
 11:             AAA aaa= new AAA();
 12:             return aaa;
 13:         }
 14:      }
 15:     public class Program
 16:     {
 17:         public static void Main(string[] args)
 18:         {
 19:         }
 20:     }
 21: }

编译结果:

Inconsistent accessibility: return type 'AccessModifiers.AAA' is less accessible than method 'AccessModifiers.BBB.MethodB()'

这样也编译不通过,因为AAA为internal的访问类型,在public BBB中返回了public的AAA,则意味着在其他程序集中也可能访问AAA,这样是违法了internal修饰符原则,故编译报错。

同理,如下的代码也是一样的问题导致编译报错:

  1:  namespace AccessModifiers
  2: {
  3:     class AAA
  4:     {
  5:
  6:     }
  7:     public class BBB
  8:     {
  9:         public AAA aaa;
 10:     }
 11:     public class Program
 12:     {
 13:         public static void Main(string[] args)
 14:         {
 15:         }
 16:     }
 17: }

如对代码做重构,去掉BBB中AAA变量的修饰,既默认为private访问修饰符,则编译没有错误了。

  1:  namespace AccessModifiers
  2: {
  3:     class AAA
  4:     {
  5:
  6:     }
  7:     public class BBB
  8:     {
  9:          AAA a;
 10:     }
 11:     public class Program
 12:     {
 13:         public static void Main(string[] args)
 14:         {
 15:         }
 16:     }
 17: }

参考MSDN中修饰符说明:

public

同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。

private

只有同一类或结构中的代码可以访问该类型或成员。

protected

只有同一类或结构或者此类的派生类中的代码才可以访问的类型或成员。

internal

同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。

protected internal

由其声明的程序集或另一个程序集派生的类中任何代码都可访问的类型或成员。 从另一个程序集进行访问必须在类声明中发生,该类声明派生自其中声明受保护的内部元素的类,并且必须通过派生的类类型的实例发生。

同时,C#中类、枚举、结构体等修饰符规则表如下:

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

Sealed Classes

Sealed修饰符的类,不可被其他类继承。

  1:  namespace AccessModifiers
  2: {
  3:     sealed class AAA
  4:     {
  5:
  6:     }
  7:     class BBB:AAA
  8:     {
  9:
 10:     }
 11:     public class Program
 12:     {
 13:         public static void Main(string[] args)
 14:         {
 15:         }
 16:     }
 17: }

运行报错:

'AccessModifiers.BBB': cannot derive from sealed type 'AccessModifiers.AAA'

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)

Sealed类使用如下:

  1: using System;
  2:
  3: namespace AccessModifiers
  4: {
  5:     sealed class AAA
  6:     {
  7:         public int x = 100;
  8:         public void MethodA()
  9:         {
 10:             Console.WriteLine("Method A in sealed class");
 11:         }
 12:     }
 13:     public class Program
 14:     {
 15:         public static void Main(string[] args)
 16:         {
 17:             AAA aaa=new AAA();
 18:             Console.WriteLine(aaa.x);
 19:             aaa.MethodA();
 20:             Console.ReadKey();
 21:         }
 22:     }
 23: }

运行正常。

Constants

  1: public class Program
  2:     {
  3:         private const int x = 100;
  4:         public static void Main(string[] args)
  5:         {
  6:             Console.WriteLine(x);
  7:             Console.ReadKey();
  8:         }
  9:     }

运行结果:

100

结论,Const变量在初始化的时候设定了初始值,可被使用,但不可修改值。同时const变量支持互相引用运算。

  1:  using System;
  2:
  3: namespace AccessModifiers
  4: {
  5:     public class Program
  6:     {
  7:         private const int x = y + 100;
  8:         private const int y = z - 10;
  9:         private const int z = 300;
 10:
 11:         public static void Main(string[] args)
 12:         {
 13:            System.Console.WriteLine("{0} {1} {2}",x,y,z);
 14:             Console.ReadKey();
 15:         }
 16:     }
 17: }

但是请不要循环依赖,否则编译器会检测报错:

  1: using System;
  2:
  3: namespace AccessModifiers
  4: {
  5:     public class Program
  6:     {
  7:         private const int x = y + 100;
  8:         private const int y = z - 10;
  9:         private const int z = x;
 10:
 11:         public static void Main(string[] args)
 12:         {
 13:            System.Console.WriteLine("{0} {1} {2}",x,y,z);
 14:             Console.ReadKey();
 15:         }
 16:     }
 17: }

检测报错:

The evaluation of the constant value for 'AccessModifiers.Program.x' involves a circular definition

本篇小结

  1. Class成员的默认修饰符为private
  2. class 被标记为internal仅能被当前程序集访问.
  3. Namespace默认为public修饰符,且不能添加修饰符。
  4. class可以使用public 或 internal修饰符.不能使用修饰符 protected private. class默认的修饰符为internal.
  5. 类成员可使用所有修饰符,默认为 private.
  6. Protected internal修饰符约定了仅在继承类内有效.
  7. 在public 与 internal修饰符之间,public通常有更大的访问权限.
  8. 基类必须必子类有更大的修饰符访问权限,才可被子类继承.
  9. 函数返回值的修饰符要有能访问返回值的权限.
  10. sealed Class无法被子类继承.
  11. const变量,需要在声明时完成初始化,在编码阶段不能初始化.
  12. 类的const变量,可以彼此引用,但是不能形成循环引用.
  13. const变量在编译器进行初始化,故const的运算可被执行.
  14. const变量不能被标记为static.
  15. Static 变量在类首次被加载时候初始化. int类型默认初始化为0,bool被初始化为False.
  16. static readonly 字段无法被赋值,static构造函数或者变量初始化时刻除外.

参考原文:Diving into OOP (Day 5): All About C# Access Modifiers (Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields)

文章目录:

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)的更多相关文章

  1. 访问修饰符(public,private,protected,internal,sealed,abstract)

    为了控件C#中的对象的访问权限,定义对象时可以在前面添加修饰符. 修饰符有五种:private(私有的),protected(受保护的),internal(程序集内部的),public(公开的),以及 ...

  2. C#访问修饰符(public,private,protected,internal,sealed,abstract)

    为了控件C#中的对象的访问权限,定义对象时可以在前面添加修饰符. 修饰符有五种:private(私有的),protected(受保护的),internal(程序集内部的),public(公开的),以及 ...

  3. 访问修饰符public,private,protected,以及不写(默认)时的区别?

    private: 1.在当前类开发中,main方法之外可以直接借助名字使用,当前类的main方法中可以使用对象打点的方式直接使用成员. 2.在当前类之外,使用对象(或是类名,针对静态的)打点调用都是被 ...

  4. 访问修饰符 public private protected default

  5. 12、类成员访问修饰符public/private/producted/readonly

    1.private 类的私有成员 private 类的私有成员,只能在内部访问,在外部访问不到,无法被继承,我们可以将不需要被外部修改的定义为私有的 私有成员,只能在内部访问,在外部访问不到 priv ...

  6. 关于Java的权限修饰符(public,private,protected,默认friendly)

    以前对访问修饰符总是模棱两可,让自己仔细解释也是经常说不很清楚.这次要彻底的搞清楚. 现在总结如下: 一.概括总结 各个访问修饰符对不同包及其子类,非子类的访问权限 Java访问权限修饰符包含四个:p ...

  7. 2018/03/10 每日一学PHP 之 修饰符 public/private/protected

    对于面向对象 修饰符的使用是我们最常用,也是很容易忽略的小细节. 对于编程来说,把握好每一个小细节,就能构造出漂亮,优雅的程序. public 使用最多的修饰符,公共方法,允许所有访问,就像一个公交车 ...

  8. Java修饰符 public、protected、default、private

    2.访问修饰符public,private,protected,以及不写(默认)时的区别?答: 修饰符 当前类 同 包 子 类 其他包 public √ √ √ √ protected √ √ √ × ...

  9. C#中五种访问修饰符作用范围 public、private、protected、internal、protected internal

    1.五种访问修饰符包括哪些? public.private.protected.internal.protected internal 2.五种访问修饰符的作用范围? public  :公有访问.不受 ...

随机推荐

  1. python核心编程学习记录之执行环境

  2. Atitit vod ver 12 new feature v12 pb2 影吧 视频 电影 点播 播放系统v12新特性

    Atitit vod ver 12 new feature v12 pb2 影吧 视频 电影 点播 播放系统v12新特性 项目分离从独立的se ver Run mode from brow ex to ...

  3. Linux常用性能检测命令解释

    1.uptime [root@smgsim02 ~]# uptime 15:08:15 up 98 days, 4:19, 2 users, load average: 0.07, 0.29, 0.1 ...

  4. Android studio 下的 NDK 配置方法和注意事项

    http://blog.csdn.net/u013598660/article/details/47341963

  5. Prefix.pch的作用和用法

    一般用于放置宏,省去xcode编译的时间 Hello World_Prefix.pch:扩展名.pch表示"precompiled header",这是一个你工程要用到的来自于外部 ...

  6. poj A Round Peg in a Ground Hole

    http://poj.org/problem?id=1584 #include<cstdio> #include<cstring> #include<cmath> ...

  7. 构件图(Component Diagram)—UML图(八)

    构件图是显示代码自身结构的实现级别的图表.构件图由诸如源码文件.二进制代码文件.可运行文件或动态链接库 (DLL) 这种构件构成,并通过依赖关系相连接 以下这张图介绍了构件图的基本内容: 以下这张图是 ...

  8. CollectioView滚动到指定section的方法

    项目中的需求:collectionView顶部有一个scrollView组成的标签,点击标签,让collectionView滚动到指定的行,滚动collectionView自动切换到顶部指定的标签 实 ...

  9. url重定向或者重写

    有四种方式:1.urlMappings,返回200状态码 <system.web> <urlMappings > <add url="~/others.aspx ...

  10. Git bash 配置多个远端仓库

    $ cat .ssh/config #aliyeye Host aliyeye.com.cn HostName aliyeye.com.cn PreferredAuthentications publ ...