深入浅出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-10-27 10:51:06

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

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

为了控件C#中的对象的访问权限,定义对象时可以在前面添加修饰符. 修饰符有五种:private(私有的),protected(受保护的),internal(程序集内部的),public(公开的),以及protectde internal(只有本程序内或者继承于该类的类型可以访问). 可以使用修饰符的对象:namespace(命名空间),class(类),struct(结构),enum(枚举),interface(接口),delegate(委托),function(函数),变量 1.public:

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

深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants) 访问修饰符(或者叫访问控制符)是面向对象语言的特性之一,用于对类.类成员函数.类成员变量进行访问控制.同时,访问控制符也是语法保留关键字,用于封装组件. Public, Private, Protected at Class Level 在创建类时,我们需要考虑类的作用域范围,如谁可访问该类,谁可访问该类成员变量,谁可访问该类成员函数. 换而言之,我们需

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

答: 修饰符 当前类 同包 子类 其他包public    √   √    √   √protected   √  √    √  ×default  √  √    ×  ×private  √  ×    ×  × 类的成员不写访问修饰时默认为default.默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private).受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有.Java中,外部类的修饰符只能是p

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

类的成员不写访问修饰时默认为default.默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private).受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有. 总结如下表 原文地址:https://www.cnblogs.com/TomJay/p/9571202.html

Java修饰符public private protected 默认

Java中访问修饰符public.private.protecte.default的意义讲解: public(接口访问权限): Java语言中访问限制最宽的修饰符,一般称之为“公共的”.被其修饰的类.属性以及方法不仅可以跨类访问,而且允许跨包(package)访问.private(你无法访问): Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”.被其修饰的类.属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问.protected(继承访问权限): 介于publi

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

1.private 类的私有成员 private 类的私有成员,只能在内部访问,在外部访问不到,无法被继承,我们可以将不需要被外部修改的定义为私有的 私有成员,只能在内部访问,在外部访问不到 private 可以在类的内部访问私有成员,不能再外部访问,但是在外部可以访问这个getType,从而访问到type,方法也是默认public公开的 私有成员无法被继承  2.protected受保护的 和private类似,也是私有成员,只能在内部访问,外部无法访问,但是可以被继承 可以被继承,但是只能在

Java修饰符public private protected和default(friendly)之间的区别

对于public修饰符,它具有最大的访问权限,可以访问任何一个在CLASSPATH下的类.接口.异常等.它往往用于对外的情况,也就是对象或类对外的一种接口的形式. 对于protected修饰符,它主要的作用就是用来保护子类的.它的含义在于子类可以用它修饰的成员,其他的不可以,它相当于传递给子类的一种继承的东西. 对于default来说,有点的时候也成为friendly(友员),它是针对本包访问而设计的,任何处于本包下的类.接口.异常等,都可以相互访问,即使是父类没有用protected修饰的成员

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

对于面向对象 修饰符的使用是我们最常用,也是很容易忽略的小细节. 对于编程来说,把握好每一个小细节,就能构造出漂亮,优雅的程序. public 使用最多的修饰符,公共方法,允许所有访问,就像一个公交车一样,上来交钱[参数],有钱就行,无所谓是谁. 对于这个修饰符救不在做更多的解释了,因为他的使用实在是太多了. PS:如果一个方法没有定义修饰符,那么在PHP5中,默认是public. private 私有方法, 不允许在直接实例化后访问,子类也不能直接访问,只允许在自己的类中使用. 道理我都懂,我

C#的五种访问修饰符

简述: 所有类型和类型成员都具有可访问性级别,用来控制是否可以在您程序集的其他代码中或其他程序集中使用它们. 可使用访问修饰符指定声明类型或成员的可访问性. 在C#语言中,共有五种访问修饰符:public.private.protected.internal.protected internal. 作用范围如下表: 五种修饰符的作用范围 原文地址:https://www.cnblogs.com/zquan/p/9743836.html