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是直正意義上的重載.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM