天天看點

C#類的嵌套

嵌套類(Nested Class)是在類中定義的類。以下把擁有内嵌類的類稱為外部類。嵌套類分為靜态嵌套類和非靜态嵌套類,其中非靜态嵌套類也被稱為内部類。嵌套類在UML中是composite的另外一種代碼表示形式,表示耦合度更高,并且與外部類更加緊密。

一般類的通路修飾符可以定義為預設的internal或者public,而内嵌類就有比較多的選擇,可以是為protected、internal、public以及預設的private。

内嵌類與外部類的通路限制

嵌套類可以通路外部類的方法、屬性、字段而不管通路修飾符的限制。如:

  public class A

  {

      private static int _AInt;

      private int _instanceInt;

      private static void AMethod()

      {

          Console.WriteLine(_AInt);

      }

      public void SayIt()

      {

          NestedA.Method(this);

      }      

      private class NestedA

      {

         public static void Method(A a)

         {

            //靜态成員

            _AInt = 100;

            AMethod();

            //執行個體成員

            a._instanceInt = 10;

            a.SayIt();

         }

      }

  }

  但是外部類隻能夠通路修飾符為public、internal嵌套類的字段、方法、屬性。示例如下:

  public class A

  {

     public static void AMethod()

     {

        //成功

        NestedA.StaticMethod();

        //編譯報錯

        NestedA._Int = 100;       

        NestedA ins=new NestedA();

        //成功

        ins.Method();

        //編譯報錯

        ins._instanceInt = 100;

     }

     private class NestedA

     {

        private static int _Int;

        private int _instanceInt;

        public static void StaticMethod() { }

        public void Method(){}

     }

  }

  嵌套類通路外部類執行個體的方法、字段、屬性時候。一般在采取構造函數輸入外部類。如下:

  public class A

  {

     private int _a;

     private class NestedA

     {

        public NestedA(A a)

        {

           a._a = 9;

        }             

     }

  }

繼承

繼承類,也就是繼承類外部類的類,隻能使用父類中嵌套類的public或者internal(同一個程式集合)方法。但是繼承類可以再定義一個内嵌類并從繼承父類中嵌套類。如:

  public class A

  {

     protected class Nested

     {

        protected virtual void BaseNested_Method(){}

     }

  }

  public class C : A

  {   

    protected class C_Nested:Nested

    {

       protected override void BaseNested_Method()

       {

           //重寫部分

       }

    }

  }

因為C中A中繼承,是以C_Nested可以繼承Nested類,進而擷取重寫父嵌套類的機會。但是Nested必須是可繼承類及可通路的(非private 、sealed、static)。

嵌套類可以随意通路外部類的任何資料屬性,而外部類通路嵌套類就隻能遵守通路修飾符。從這個角度看,嵌套類是外部類的補充,通過嵌套類可以擷取更好的封裝性,增加外部類的可維護性和可讀性。      

從程式結構看,嵌套類在邏輯上更加接近使用類。可以更有效地表示類與類之間的緊密程度。為類管理提供除命名空間外的另一種方法。

懶加載

嵌套類的靜态構造函數不會随着外部類的觸發而初始化。是以可以有效地避免建立時候初始化時間,當需要使用内嵌類的時候,嵌套類才開始初始化。

 public class Outside

 {

    static Outside()

    {

       Console.WriteLine("Outside Inilizlized");

    }

    public void SayIt()

    {

        Nested.Run();

    }

    private class Nested

    {

        static Nested()

        {

            Console.WriteLine("Nested initilized");

        }

        public static void Run()

        {

            Console.WriteLine("Nested Run");

        }

    }

}

執行結果

Outside o = new Outside(); //列印"Outside Inilizlized"

Console.ReadLine();

o.SayIt();//首先列印"Nested initilized" 再列印 "Nested Run"

Console.ReadLine();

一般應用這個特性會在一些C#單例模式中找到,而這種模式可以被稱為Fully lazy singleton模式。下面是簡單的示範代碼(Singleton模式可以在這裡有更加詳細的解釋):

  public class Singleton

  {

      public static Singleton Instance

      {

         get { return Nested.instance; }

      }

      private class Nested

      {

          public readonly static Singleton instance=new Singleton();

      }

  }

 反射

 反射内嵌類需要使用"+"而不是我們常使用的"." ,如A類在名稱為InsideClass的Assembly中。

 namespace InsideClass

 {

    public class A

    {

        public class Nested

        {

            protected void BaseNested_Method()

            {

            }

        }

     }

 }

執行

//成功

object o1 = System.Activator.CreateInstance("InsideClass", "InsideClass.A+Nested");

//失敗 抛出System.TypeLoadException異常

object o2 = System.Activator.CreateInstance("InsideClass", "InsideClass.A.Nested");

c#