深入浅出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#中类、枚举、结构体等修饰符规则表如下:

 

 

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

 

本篇小结

  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)

 

文章目录:

时间: 2024-08-02 14:23:19

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

这个Public Stop(){} 类中 有很多个没有访问修饰符的方法 请问这些方法的作用是干嘛的啊

问题描述 publicvoidStop(){this.threadNeedQuit=true;while(this.thread!=null&&this.thread.ThreadState!=ThreadState.Stopped)Thread.Sleep(1);this.thread=null;this.waitingOrderList.CollectionChanged-=this.waitingOrderList_CollectionChanged;this.UnloadDevic

C#的基类和访问修饰符

C#的基类和访问修饰符 一. C#的基类System. Object 在面向对象编程过程中,所有的类都是超级父类System. Object类的子类.所有的类都自动继承System. Object,自然也就继承了System. Object类的所有方法,System. Object包含的方法有: public static bool Equals(object objA,object objB){}    public static bool ReferenceEquals(object obj

c#-C#的四种访问修饰符是什么?是不是public、protected...

问题描述 C#的四种访问修饰符是什么?是不是public.protected... C#的四种访问修饰符是什么?是不是public.protected... 解决方案 访问修饰符(C# 参考) Visual Studio 2005 其他版本 访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性.本节介绍四个访问修饰符:publicprotectedinternalprivate使用这些访问修饰符可指定下列五个可访问性级别:public:访问不受限制.protected:访问仅限于包含类或从

简介php的public、private和protected访问修饰符

PHP中有三种访问修饰符,分别是: public(公共的.默认) protected(受保护的) private(私有的) public(公共的.默认)在PHP5中如果类没有指定成员的访问修饰符,默认就是public的访问权限 . protected(受保护的)被声明为protected的成员,只允许该类的子类进行访问. private(私有的 ) 被定义为private的成员,对于类内部所有成员都可见,没有访问限制.对类 外部不允许访问. 图解 查看本栏目更多精彩内容:http://www.b

php面向对象public private protected 访问修饰符

本篇文章是对php面向对象public private protected 访问修饰符进行了详细的分析介绍,需要的朋友参考下   PHP中有三种访问修饰符,分别是: public(公共的.默认) protected(受保护的) private(私有的)public(公共的.默认)在PHP5中如果类没有指定成员的访问修饰符,默认就是public的访问权限. protected(受保护的)被声明为protected的成员,只允许该类的子类进行访问. private(私有的 ) 被定义为private

浅谈php中的访问修饰符private、protected、public的作用范围_php实例

1. private 只能在类内部使用 2. protected 可以在类内部和继承类里使用.类外部不能使用[即实例化后的对象无法调用] 3. public 全部范围适用. 4.子类复写父类中的方法时,子类中的 访问修饰符的范围要大于等于 父类的[ 继承只能发扬光大,至少保持不变.不可以丢失东西.]

浅谈php中的访问修饰符private、protected、public的作用范围

1. private 只能在类内部使用 2. protected 可以在类内部和继承类里使用.类外部不能使用[即实例化后的对象无法调用] 3. public 全部范围适用. 4.子类复写父类中的方法时,子类中的 访问修饰符的范围要大于等于 父类的[ 继承只能发扬光大,至少保持不变.不可以丢失东西.] 以上这篇浅谈php中的访问修饰符private.protected.public的作用范围就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家.

关于访问修饰符的,高手看过来.

问题描述 Ybjk.Iini接口的访问修饰符是internal.奇怪怎么回事啊?这几个类都是一个程序集的. 解决方案 解决方案二:自已顶一个,别沉喽解决方案三:再顶一次啊!解决方案四:你的冒号右边使用的那个类型,在这里不能访问,你应该检查那个类型的class前边的修饰符.解决方案五:ybjk.Iini接口的访问修饰符是internal.并且是一个程序集解决方案六:internal的可访问性应该大于internalprotected的啊!怎么回事解决方案七:引用5楼lilei_new的回复: in

关于Java中各种修饰符与访问修饰符的说明

访问 补充一下JAVA的基础知识(转)关于Java中各种修饰符与访问修饰符的说明 类:访问修饰符  修饰符  class 类名称 extends 父类名称 implement 接口名称 (访问修饰符与修饰符的位置可以互换) 访问修饰符 名称 说明 备注 public 可以被所有类访问(使用) public类必须定义在和类名相同的同名文件中 package 可以被同一个包中的类访问(使用) 默认的访问权限,可以省略此关键字,可以定义在和public类的同一个文件中   修饰符 名称 说明 备注 f