为什么我会需要使用C#嵌套类

我想了解在C#中的嵌套类。 我知道嵌套类是在另一个类中定义的类,我不明白为什么我需要这样做。

我特别喜欢的模式是将嵌套类与工厂模式结合起来:

public abstract class BankAccount { private BankAccount() {} // prevent third-party subclassing. private sealed class SavingsAccount : BankAccount { ... } private sealed class ChequingAccount : BankAccount { ... } public static BankAccount MakeSavingAccount() { ... } public static BankAccount MakeChequingAccount() { ... } } 

通过嵌套这样的类,我使第三方不可能创build自己的子类。 我完全控制了在任何bankaccount对象中运行的所有代码。 而我所有的子类都可以通过基类共享实现细节。

目的通常只是为了限制嵌套类的范围 。 与普通类相比,嵌套类有private修饰符的可能性(当然也有protected )。

基本上,如果你只需要在“父”类中使用这个类(就范围而言),那么通常将它定义为一个嵌套类。 如果这个类可能需要在没有程序集/库的情况下使用,那么用户将它定义为一个单独的(兄弟)类通常会更方便,不pipe这两个类之间是否存在任何概念关系。 尽pipe在技术上可以创build一个嵌套在public父类中的public类,但在我看来这很less是一个合适的东西来实现。

嵌套类可以有privateprotectedprotected internal访问修饰符以及publicinternal

例如,您正在实现返回IEnumerator<T>对象的GetEnumerator()方法。 消费者不会关心对象的实际types。 他们所知道的就是它实现了这个接口。 你想要返回的类没有任何直接的用途。 您可以将该类声明为private嵌套类并返回它的一个实例(实际上C#编译器是如何实现迭代器的):

 class MyUselessList : IEnumerable<int> { // ... private List<int> internalList; private class UselessListEnumerator : IEnumerator<int> { private MyUselessList obj; public UselessListEnumerator(MyUselessList o) { obj = o; } private int currentIndex = -1; public int Current { get { return obj.internalList[currentIndex]; } } public bool MoveNext() { return ++currentIndex < obj.internalList.Count; } } public IEnumerator<int> GetEnumerator() { return new UselessListEnumerator(this); } } 

我不明白为什么我会需要这样做

我想你永远不需要这样做。 鉴于这样的嵌套类…

 class A { //B is used to help implement A class B { ...etc... } ...etc... } 

…你总是可以将内部/嵌套类移动到全局范围,像这样…

 class A { ...etc... } //B is used to help implement A class B { ...etc... } 

但是,当B仅用于帮助实现A时,则使B成为内部/嵌套类有两个优点:

  • 它不会污染全球范围(例如客户代码可以看到A不知道B类甚至存在)
  • B的方法隐式地访问A的私有成员; 而如果B不是嵌套在A内,B就不能访问A的成员,除非这些成员是内部的或公共的; 但是让这些成员内部或者公开也会让他们接触到其他类(不仅仅是B)。 所以相反,保持A私有的这些方法,让B通过声明B为嵌套类来访问它们。 如果你了解C ++,这就好像在C#中所有的嵌套类都自动成为它所包含的类的“ 朋友 ”(而且,声明一个嵌套的类是唯一的方法来声明C#中的友谊,因为C#没有friend关键字)。

当我说B可以访问A的私有成员时,假定B有一个对A的引用; 它经常这样做,因为嵌套类通常是这样声明的…

 class A { //used to help implement A class B { A m_a; internal B(A a) { m_a = a; } ...methods of B can access private members of the m_a instance... } ...etc... } 

…和使用这样的代码A的方法构造…

 //create an instance of B, whose implementation can access members of self B b = new B(this); 

你可以在Mehrdad的回答中看到一个例子。

公共嵌套成员也有很好的用处

嵌套类可以访问外部类的私有成员。 所以创build比较器(即实现IComparer接口)时,这是正确的方法。

在这个例子中,FirstNameComparer可以访问private _firstName成员,如果该类是一个单独的类,则不会

 public class Person { private string _firstName; private string _lastName; private DateTime _birthday; //... public class FirstNameComparer : IComparer<Person> { public int Compare(Person x, Person y) { return x._firstName.CompareTo(y._lastName); } } } 

有时候实现一个从类内部返回的接口是有用的,但是这个接口的实现应该完全从外部隐藏起来。

举一个例子 – 在向C#添加yield之前,实现枚举器的一种方法是将枚举器的实现作为私有类实现在集合中。 这样可以方便地访问collections的成员,但是外部世界不需要/看到如何实现的细节。

嵌套类对于实现不应该暴露的内部细节非常有用。 如果你使用Reflector来检查像Dictionary <Tkey,TValue>或Hashtable类,你会发现一些例子。

也许这是什么时候使用嵌套类的一个很好的例子?

 // ORIGINAL class ImageCacheSettings { } class ImageCacheEntry { } class ImageCache { ImageCacheSettings mSettings; List<ImageCacheEntry> mEntries; } 

和:

 // REFACTORED class ImageCache { Settings mSettings; List<Entry> mEntries; class Settings {} class Entry {} } 

PS:我没有考虑应该使用哪些访问修饰符(私有,受保护,公共,内部)