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

214 c# nested-class inner-classes

我试图了解C#中的嵌套类.我知道嵌套类是在另一个类中定义的类,我没有得到的是为什么我需要这样做.

Eri*_*ert 263

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

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() { ... }
}
Run Code Online (Sandbox Code Playgroud)

通过嵌套这样的类,我让第三方无法创建自己的子类.我完全控制在任何bankaccount对象中运行的所有代码.我的所有子类都可以通过基类共享实现细节.

  • 对.私人意味着可以在类型中访问.根据定义,嵌套成员在类型中. (5认同)

Nol*_*rin 114

目的通常只是限制嵌套类的范围.与普通类相比,嵌套类具有private修饰符的额外可能性(protected当然也是如此).

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

  • 实际上,.NET Framework准则明确建议不要创建公共嵌套类. (41认同)
  • MS不遵守自己的建议的另一个例子:只需看看`System.Windows.Forms.ListView`嵌套类! (4认同)
  • 更好的MSDN文章 - http://msdn.microsoft.com/en-us/library/ms229027.aspx (4认同)
  • @Henk:我认为Mark指的是这个页面:http://msdn.microsoft.com/en-us/library/tdz1bea9(VS.71).aspx (3认同)

Meh*_*ari 51

嵌套类可以有private,protectedprotected internal连同访问修饰符publicinternal.

例如,您正在实现GetEnumerator()返回IEnumerator<T>对象的方法.消费者不关心对象的实际类型.他们所知道的就是它实现了这个界面.您要返回的课程没有任何直接用途.您可以将该类声明为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • Mehrdad:你能编辑你的答案,包括一个定义其枚举器类型的IEnumerable类的例子吗?我会这样做,但它属于你的答案或里德的. (2认同)

Chr*_*isW 45

我没有得到的是为什么我需要这样做

我想你永远不需要这样做.给定一个这样的嵌套类......

class A
{
  //B is used to help implement A
  class B
  {
    ...etc...
  }
  ...etc...
}
Run Code Online (Sandbox Code Playgroud)

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

class A
{
  ...etc...
}

//B is used to help implement A
class B
{
  ...etc...
}
Run Code Online (Sandbox Code Playgroud)

但是,当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...
}
Run Code Online (Sandbox Code Playgroud)

...并使用这样的代码从A的方法构造......

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

你可以在Mehrdad的回复中看到一个例子.


Arj*_*nbu 31

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

嵌套类可以访问外部类的私有成员.因此,这是正确的方式,即创建Comparer(即实现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);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 18

有时候实现一个将从类中返回的接口很有用,但是该接口的实现应该完全隐藏在外部世界之外.

作为一个例子 - 在向C#添加yield之前,实现枚举器的一种方法是将枚举器的实现作为集合中的私有类.这将提供对集合成员的轻松访问,但外部世界不需要/查看如何实现它的细节.


Fer*_*ndo 5

嵌套类对于实现不应公开的内部细节非常有用。如果使用Reflector检查诸如Dictionary <Tkey,TValue>或Hashtable之类的类,则会找到一些示例。