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

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

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

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

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

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

      [5] 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:(这里同一个程序集指同一个命名空间)

    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;   
        }
    }
    
    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 成员,因为他们在同一个程序集里

    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个声明修饰符

      [1] Partial:在整个同一程序集中定义分部类和结构。

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

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

      [4] Sealed:指定类不能被继承。

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

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

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

      [8] 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是直正意义上的重载.  

  • 相关阅读:
    插入排序
    选择排序
    P1338 末日的传说 逆序数对
    P1582倒水 位运算
    P2158 [SDOI2008] (欧拉函数
    HDU 6274 二分+预处理(CCPC K题
    P1219 N皇后
    [USACO1.5] 回文质数
    Codeforces #123D: 后缀数组+单调栈
    单调栈 单调队列
  • 原文地址:https://www.cnblogs.com/xinaixia/p/5775471.html
Copyright © 2011-2022 走看看