zoukankan      html  css  js  c++  java
  • C# 中4个访问符和8个修饰符详解

    4个访问修饰符(是添加到类、结构或成员声明的关键字)

    Public:公有的,是类型和类型成员的访问修饰符。对其访问没有限制。

    Internal:内部的,是类型和类型成员的访问修饰符。同一个程序集中的所有类都可以访问

    Private:私有的,是一个成员访问修饰符。只有在声明它们的类和结构中才可以访问。

    Protected::受保护的,是一个成员访问修饰符。只能在它的类和它的派生类中访问。

        protected internal:访问级别为 internal 或 protected。即,“同一个程序集中的所有类,以及所有程序集中的子类都可以访问

    注意点:

      一个成员或类型只能有一个访问修饰符,使用 protected internal组合时除外。

          如果在成员声明中未指定访问修饰符,则使用默认的可访问性

       类型成员默认的可访问性

    属于

    默认的成员可访问性

    该成员允许的声明的可访问性

    enum

    public

    class

    private

    public

    protected

    internal

    private

    protected internal

    interface

    public

    struct

    private

    public

    internal

    private

           

    Internal 和protected internal 详解(即什么是同一个程序集)

     

      示例1:(这里同一个程序集指同一个命名空间)

    Class1:

     using System;

    using System.Collections.Generic;

    using System.Text;

    namespace Example05Lib

    {    

    public class Class1   

     {       

     internal String strInternal = null;       

    public String strPublic;       

    internal protected String strInternalProtected = null;   

    }

    }

    Class2:

    using System; using System.Collections.Generic; using System.text

    namespace Example05Lib {    class Class2  {    private String tmpStr=new Class1().strInternal;    private String tmpStr=new Class1().strInternalProtected;    private String tmpStr=new Class1().strPublic;  } }

    1.1结果: Class2 类可以访问到 Class1 的 strInternal 成员,当然也可以访问到 strInternalProtected 成员,因为他们在同一个程序集里

     

    Class3:

    using System; using System.Collections.Generic; using System.text using Example05Lib

    namespace Example05  {   class Program   {      class Class3:Class1      {         public Class3()          {             base.StrInternalProtected;              base.strPublic;           }         }   } }

    1.2结果:Class3 类无法访问到 Class1 的 strInternal 成员,因为它们不在同一个程序集里。但却可以访问到 strInternalProtected成员,因为 Class3 是 Class1 的继承类。

     

    using System; using System.Collections.Generic; using System.text using Example05Lib namespace Example05  { class Program {    static void Main(string[] args)    {       String tmpStr=new Class1().strPublic;     } } }

    1.3结果:无法访问到 strInternalProtected 与strInternal 成员,因为它们既不在同一个程序集里也不存在继承关系

     

    示例2(在这里同一个程序集是指同一个.cs文件,不同的.cs文件的命名空间省略)

     

    2.1该示例包含两个文件:Assembly1.cs 和 Assembly2.cs。第一个文件包含内部基类 BaseClass。在第二个文件中,实例化BaseClass 的尝试将产生错误。

    internal class BaseClass

    {

       public static int intM = 0;

    }

    class TestAccess

    {

       static void Main()

       {

          BaseClass myBase = new BaseClass();   // CS0122

       }

    }

    2.2 使用与示例 1 中所用的文件相同的文件,并将 BaseClass 的可访问性级别更改为 public。还将成员 IntM 的可访问性级别更改为 internal。在此例中,您可以实例化类,但不能访问内部成员。

    public class BaseClass

    {

       internal static int intM = 0;

    }

    public class TestAccess

    {

       static void Main()

       {

          BaseClass myBase = new BaseClass();   // Ok.

          BaseClass.intM = 444;    // CS0117

       }

    }

    示例3

    对于一些大型的项目,通常由很多个DLL文件组成,引用了这些DLL,就能访问DLL里面的类和类里面的方法。比如,你写了一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能,这个DLL文件的程序就是一个程序集。

    如果你记录日志的程序集是这么定义的

    namespace LogerHelper

    {

        internal class aa

        {

             public void bb()

             {

                 return "";

             }

        }

        public class Write

        {

            public void WriteIn(string content)

            {

                class x = new aa();   

                x.bb();

            }

        }

    }

    当另一个项目引用了此DLL

    它可以这么访问 

    LogerHelper.Write x = new LogerHelper.Write();

    x.WriteIn("");

    但不可以这么访问

    LogerHelper.aa x = new LogerHelper.aa();

    x.bb();

    这就叫,只能在程序集中访问

    8个声明修饰符

      

       Partial:在整个同一程序集中定义分部类和结构,详解见问题1。

       Static: 声明属于类型本身而不是属于特定对象的成员。

       Abstract:抽象类,只能是其他类的基类。类中的方法只声明不实现,方法的实现在他的派生类中完成。

       Sealed:指定类不能被继承。

       Virtual:用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象

    Override:提供从基类继承的成员的新实现

    New:作修饰符,隐藏从基类成员继承的成员,在不使用 new 修饰符的情况下隐藏成员是允许的,但会生成警告。作运算符,用于创建对象和调用构造函数。

       Extern:用于声明在外部实现的方法。 extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 特性一起使用。 在这种情况下,还必须将方法声明为 static

       Virtual,override和new 的区别

    1.       virtual和override配套使用。在基类base中声明了虚方法method()并用virtual修饰,在子类derived中重写方法method()并用override修饰。那么当将子类的实例赋予基类的对象(不需要强制转换)时即Base Bclass= new Derived();Bclass.Method()是调用了子类的method()方法,而不是基类的。所以

    2.       new不需要和virtual配套使用。在基类base中声明了方法method(),在子类derived中声明了同名的方法method()并用new修饰。那么当将子类的实例赋予基类的对象时即Base Bclass= new Derived();Bclass.Method()是调用了基类类的method()方法,而不是子类的。

    3.       这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已.

    下面,我以例子来说明他们之间的微妙区别:

    public class GrandClass//基类 {         public GrandClass()         {                 Console.WriteLine("In GrandClass.Constructor");         }         public virtual void Method()//用virtual才可以在子类中用override,而new不需要这样         {                 Console.WriteLine("In GrandClass.Method()");         } }
    public class ParentClass:GrandClass//继承基类,看看override状态 {         public ParentClass()         {                 Console.WriteLine("In ParentClass.Constructor");         }         public override void Method()//使用override,是说把基类的方法重新定义         {                 Console.WriteLine("In ParentClass.Method() use override");         } }
    public class NewParentClass:GrandClass//继承基类,看看new状态 {         public NewParentClass()         {                 Console.WriteLine("In NewParentClass.Constructor");         }         new public void Method()//使用new,不是说用到基类的方法,而是重新定义一个子类方法,只不过,方法名称与基类相同         {                 Console.WriteLine("In NewParentClass.Method()");         } }

      下面的调用代码:

    static void Main()  {         GrandClass Parent=(GrandClass)new ParentClass();//用override子类加框一个基类对象句柄         Parent.Method();         GrandClass NewParent=(GrandClass)new NewParentClass();//用new子类加框一个基类对象句柄         NewParent.Method();         NewParentClass NewParent1=new NewParentClass();//一个子类句柄         NewParent1.Method(); }

      结果是这样的:

    [1]In GrandClass.Constructor [2]In ParentClass.Constructor [3]In ParentClass.Method() use override [4]In GrandClass.Constructor [5]In NewParentClass.Constructor [6]In GrandClass.Method() [7]In GrandClass.Constructor [8]In NewParentClass.Constructor [9]In NewParentClass.Method()

      结果前的序号是我自己加的.为了以下的分析:   [1],[2]两句是GrandClass Parent=(GrandClass)new ParentClass();的结果.(注意一下子类构建器与基类构建器的初始化顺序)   [3]是Parent.Method();结果.   [4],[5]两句是GrandClass NewParent=(GrandClass)new NewParentClass();的结果.   [6]是NewParent.Method();的结果.   [7],[8]两句是GrandClass NewParent1=(GrandClass)new NewParentClass();的结果.   [9]是NewParent1.Method();的结果.
      这里我们可以看到,同样是用子类的对象构造一个基类句柄.结果却很明显,可以看到[3]和[6]的区别.[3]调用了子类的Method(),而[6]调用了基类的Method().   这说明,override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已.      而这一例子的基础是建立在用子类对象加框成基类对象的,目的是实现用基类句柄调用子类方法,以实现重载的多态性.   如果想调用子类的new方法,用子类的句柄(绝对不能用基类句柄)来调用.结果[9]可以看出来.   用new是在为子类定义方法名时,实在没有办法定义方法名的情况才与基类的方法相同,但这个方法只在子类中起到作用,而不影响基类的方法.也就是说,new方法就是子类新定义的方法.用override是直正意义上的重载. 

    注意:部分内容转载:http://blog.csdn.net/susan19890313/article/details/7575228

  • 相关阅读:
    随笔2
    随笔
    关于updateElement接口
    随笔1
    本地访问正常,服务器访问乱码 记录
    Redis (error) NOAUTH Authentication required.解决方法
    tomcat启动很慢 停留在 At least one JAR was scanned for TLDs yet contained no TLDs.
    微信公众号消息回复
    微信公众号 报token验证失败
    idea中web.xml报错 Servlet should have a mapping
  • 原文地址:https://www.cnblogs.com/fandong90/p/4160359.html
Copyright © 2011-2022 走看看