嵌套類(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");