深入浅出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中修饰符说明:
同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。
只有同一类或结构中的代码可以访问该类型或成员。
只有同一类或结构或者此类的派生类中的代码才可以访问的类型或成员。
同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。
protected internal
由其声明的程序集或另一个程序集派生的类中任何代码都可访问的类型或成员。 从另一个程序集进行访问必须在类声明中发生,该类声明派生自其中声明受保护的内部元素的类,并且必须通过派生的类类型的实例发生。
同时,C#中类、枚举、结构体等修饰符规则表如下:

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'

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
本篇小结
Class成员的默认修饰符为private- class 被标记为
internal仅能被当前程序集访问. - Namespace默认为public修饰符,且不能添加修饰符。
- class可以使用
public 或internal修饰符.不能使用修饰符protected、private. class默认的修饰符为internal. - 类成员可使用所有修饰符,默认为
private. Protected internal修饰符约定了仅在继承类内有效.在public 与internal修饰符之间,public通常有更大的访问权限.- 基类必须必子类有更大的修饰符访问权限,才可被子类继承.
- 函数返回值的修饰符要有能访问返回值的权限.
sealed Class无法被子类继承.const变量,需要在声明时完成初始化,在编码阶段不能初始化.- 类的const变量,可以彼此引用,但是不能形成循环引用.
const变量在编译器进行初始化,故const的运算可被执行.const变量不能被标记为static.Static 变量在类首次被加载时候初始化.int类型默认初始化为0,bool被初始化为False.static readonly 字段无法被赋值,static构造函数或者变量初始化时刻除外.
文章目录:
- 深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)
- 深入浅出OOP(二): 多态和继承(继承)
- 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)
- 深入浅出OOP(四): 多态和继承(抽象类)
深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)的更多相关文章
- 访问修饰符(public,private,protected,internal,sealed,abstract)
为了控件C#中的对象的访问权限,定义对象时可以在前面添加修饰符. 修饰符有五种:private(私有的),protected(受保护的),internal(程序集内部的),public(公开的),以及 ...
- C#访问修饰符(public,private,protected,internal,sealed,abstract)
为了控件C#中的对象的访问权限,定义对象时可以在前面添加修饰符. 修饰符有五种:private(私有的),protected(受保护的),internal(程序集内部的),public(公开的),以及 ...
- 访问修饰符public,private,protected,以及不写(默认)时的区别?
private: 1.在当前类开发中,main方法之外可以直接借助名字使用,当前类的main方法中可以使用对象打点的方式直接使用成员. 2.在当前类之外,使用对象(或是类名,针对静态的)打点调用都是被 ...
- 访问修饰符 public,private,protected,以及不写(默认) 时的区别?
修饰符 当前类 同 包 子 类 其他包 public √ √ √ √ protecte d √ √ √ × default √ √ × × private √ × × × 类的成员不写访问修饰时默认为 ...
- 访问修饰符 public private protected default
- 12、类成员访问修饰符public/private/producted/readonly
1.private 类的私有成员 private 类的私有成员,只能在内部访问,在外部访问不到,无法被继承,我们可以将不需要被外部修改的定义为私有的 私有成员,只能在内部访问,在外部访问不到 priv ...
- 关于Java的权限修饰符(public,private,protected,默认friendly)
以前对访问修饰符总是模棱两可,让自己仔细解释也是经常说不很清楚.这次要彻底的搞清楚. 现在总结如下: 一.概括总结 各个访问修饰符对不同包及其子类,非子类的访问权限 Java访问权限修饰符包含四个:p ...
- 2018/03/10 每日一学PHP 之 修饰符 public/private/protected
对于面向对象 修饰符的使用是我们最常用,也是很容易忽略的小细节. 对于编程来说,把握好每一个小细节,就能构造出漂亮,优雅的程序. public 使用最多的修饰符,公共方法,允许所有访问,就像一个公交车 ...
- Java修饰符 public、protected、default、private
2.访问修饰符public,private,protected,以及不写(默认)时的区别?答: 修饰符 当前类 同 包 子 类 其他包 public √ √ √ √ protected √ √ √ × ...
随机推荐
- 从Unity引擎过度到Unreal4引擎(最终版)
原文地址:http://demo.netfoucs.com/u011707076/article/details/44036839 前言 寒假回家到现在已经有十多天了,这些天回家不是睡就是吃....哎 ...
- asp.net TreeView控件绑定数据库显示信息
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- construction of tuples containing 0 or 1 items
[construction of tuples containing 0 or 1 items] the syntax has some extra quirks to accommodate the ...
- 【BZOJ2756】奇怪的游戏(二分,最小割)
题意: Blinker最近喜欢上一个奇怪的游戏.这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻的格子,并使这两个数都加上 1.现在 Blinker 想知道最 ...
- UTF-8 <==> unicode(WCHAR)
static int fetchWordFromUTF8(const chConstStringA& strText, WCHAR& result) { int nLength = s ...
- java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService
前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...
- C/C++语言的一些精简归纳
前言:本想直接写个关于OC语言,但觉得还是要说下C先. 先语言特性 C是面向过程的,没有类和对象概念,也就没有什么封装(这个?).继承.多态等特性. 而且是是中级语言,其编译过程包括:预编译(incl ...
- Oracle常量
Oracle是有常量的,而SqlServer是没有常量的 queryFrom constant ) := ' hello ';
- 网页中的JavaScript
变量的声明和赋值 var count;定义变量 count = 5;赋值 var” - 用于声明变量的关键字 “count” - 变量名 同时声明和赋值变量 var count = 10; 声明多个变 ...
- 問題排查:建立選單時的錯誤 errcode:65318,errmsg:must use utf-8 charset hint: [Vwda70520vr18]
目前已知:程式存檔時,將檔案編碼格式設定成 UTF-8 即可. 筆者使用的文字編輯器為 Editplus 3.51,檔案編碼格式很多帶 UTF8.Unicode 字眼的選項,選 UTF-8 即可.