代码之家  ›  专栏  ›  技术社区  ›  Amr

为什么要使用嵌套类[[副本]

  •  24
  • Amr  · 技术社区  · 7 年前

    this stackoverflow answer “私有嵌套类”可能非常有用 所以我在报纸上读到了他们的故事 articles such as this one 技术上 ,但不是 为什么? 你会用的。

    我想我会使用私有嵌套类 小助手类 它属于一个更大的类,但通常我需要另一个类的助手类,因此我只需要付出额外的努力(1)使嵌套类非嵌套或(2)使其公开,然后使用外部类前缀访问它,这两者似乎都是额外的工作,没有任何附加值的嵌套类放在首位。因此一般来说 ,也许除了让课堂更有条理地分组之外,我认为这也违背了 我来享受的清晰。

    用什么方法使用嵌套类使代码更易于管理、可读、高效?

    14 回复  |  直到 9 年前
        1
  •  31
  •   Eric Lippert    16 年前

    你已经回答了你自己的问题。当你需要一个在类之外没有意义的助手类时,使用嵌套类;特别是当嵌套类可以利用外部类的私有实现细节时。

    人们还使用嵌套类来构建迭代器或比较器之类的东西,这些东西在类之外毫无意义,通过一个众所周知的接口公开。

    我经常使用的一种模式是使用私有嵌套类来扩展它们的外部类:

    abstract public class BankAccount
    {
        private BankAccount() { }
        // Now no one else can extend BankAccount because a derived class
        // must be able to call a constructor, but all the constructors are
        // private!
        private sealed class ChequingAccount : BankAccount { ... }
        public static BankAccount MakeChequingAccount() { return new ChequingAccount(); }
        private sealed class SavingsAccount : BankAccount { ... }
    

        2
  •  11
  •   JSBÕ±Õ¸Õ£Õ¹    16 年前

    将接口返回给要隐藏其实现的调用方。

    public class Outer
    {
        private class Inner : IEnumerable<Foo>
        {
            /* Presumably this class contains some functionality which Outer needs
             * to access, but which shouldn't be visible to callers 
             */
        }
    
        public IEnumerable<Foo> GetFoos()
        {
            return new Inner();
        }
    }
    
        3
  •  7
  •   Sky Sanders    16 年前

    私有助手类就是一个很好的例子。

        4
  •  6
  •   Jouke van der Maas    16 年前

    当两个绑定值(如哈希表中的值)在内部不够,但在外部足够时,我使用它们。然后创建一个嵌套类,其中包含需要存储的属性,并通过方法仅公开其中的一小部分。

    我认为这是有意义的,因为如果没有其他人要使用它,为什么要为它创建一个外部类呢?只是说不清楚。

    partial 关键字,这是我通常做的。

        5
  •  6
  •   dlras2    16 年前

    我最近遇到的一个引人注目的例子是 Node Quadtree 例如,需要知道它如何将数据存储在其节点中,但代码的其他部分不应该关心。

        6
  •  5
  •   Dan Bryant    16 年前

    我发现了一些非常方便的案例:

    1. 正如其他人提到的,您可以通过接口公开类使用的数据,而不必公开类的完整实现。嵌套类还可以访问外部类的私有状态,这允许您编写紧密耦合的代码,而无需将紧密耦合公开(甚至在内部公开给程序集的其余部分)。

    2. 我遇到过一些情况,框架希望类从某个基类派生(例如WPF中的DependencyObject),但您希望类从另一个基类继承。通过使用从框架基类派生的私有嵌套类,可以与框架进行交互操作。因为嵌套类可以访问私有状态(创建时只需将父类的“this”传递给它),所以基本上可以通过组合来实现穷人的多重继承。

        7
  •  3
  •   Brian Gideon    16 年前

    使用此技术的一个非常常见的模式是在这样的场景中:类从其属性或方法之一返回接口或基类类型,但具体类型是私有嵌套类。考虑下面的例子。

    public class MyCollection : IEnumerable
    {
      public IEnumerator GetEnumerator()
      {
        return new MyEnumerator();
      }
    
      private class MyEnumerator
      {
      }
    }
    
        8
  •  3
  •   James Hart    16 年前

    我认为其他人已经很好地介绍了公共和私有嵌套类的用例。

    有一点我还没有看到,那就是你所关心的问题的答案 每个文件一个类 . 您可以通过使外部类部分化,并将内部类定义移动到一个单独的文件来解决这个问题。

    namespace MyNameSpace
    {
        public partial class OuterClass
        {
            // main class members here
            // can use inner class
        }
    }
    

    namespace MyNameSpace
    {
        public partial class OuterClass
        {
            private class Inner
            {
                // inner class members here
            }
        }
    }
    

    您甚至可以使用VisualStudio的项嵌套将OuterClass.Inner.cs设置为OuterClass.cs的“子级”,以避免弄乱您的解决方案资源管理器。

        9
  •  2
  •   user1228    16 年前

    在某些情况下,当我需要SRP(单一责任主体)的组合时,我通常会这样做。

    “好吧,如果SRP是你的目标,为什么不把它们分成不同的类呢? “你80%的时间都会这样做,但是如果你创建的类对外界没有用处,那又该怎么办呢?您不希望类只用于混乱程序集的API。

    “嗯,那不是什么吗 internal 是为了什么?” 当然。大约80%的病例。但是必须访问或修改公共类状态的内部类呢?例如,为了满足您的SRP连续性而被分解为一个或多个内部类的类?您必须标记所有方法和属性,以便这些方法和属性使用 内部的 类作为 内部的 也。

    没有什么。大约80%的病例。当然,现在您将类的内部接口与方法/属性混为一谈,这些方法/属性只对您先前创建的类有用。现在,您必须担心团队中其他人编写内部代码时不会以您意想不到的方式使用这些方法,从而扰乱您的状态。

        10
  •  1
  •   Muad'Dib    16 年前

    作为一个例子,它们对于 singleton pattern.

        11
  •  0
  •   Peter vdL    16 年前

    私有匿名嵌套类对于GUI中的事件处理程序非常重要。

        12
  •  0
  •   Mr. Boy    16 年前

    此外,在MFC和其他技术中,您可能需要控件/对话框具有drop目标类,这除了作为嵌套类之外没有什么意义。

        13
  •  0
  •   supercat    16 年前

    如果一个对象需要返回一些关于其状态的抽象信息,私有嵌套类可能是合适的。例如,如果Fnord支持“save context”和“restore context”方法,那么让“save context”函数返回Fnord.SavedContext类型的对象可能很有用。类型访问规则并不总是最有用的;例如,要允许Fnord访问Fnord.SavedContext的属性和方法,而不使这些属性和方法对外部人员可见,似乎很困难。另一方面,可以让Fnord.CreateSaveContext以Fnord作为参数创建一个新的Fnord.SaveContext(因为Fnord.SaveContext可以访问Fnord的内部结构),Fnord.LoadContextFrom()可以调用Fnord.SaveContext.RestoreContextTo()。