人们想要使用嵌套类的原因是什么?

Edw*_*uay 25 c# nested-class

这个stackoverflow回答中,一位评论者提到" 私有嵌套类"可能非常有用,所以我在这篇文章中阅读它们,这些文章倾向于解释嵌套类在技术上如何起作用,但不是为什么要使用它们.

我想我会使用私有嵌套类来处理属于更大类的小助手类,但是我经常需要来自另一个类的辅助类,所以我只需要额外的努力来(1)使嵌套类非-nested或(2)将其公开,然后使用外部类前缀访问它,这两者似乎都是额外的工作,没有任何附加值,因为首先使用嵌套类.因此,一般来说,我真的没有看到嵌套类的用例,除了可能将类更加有条理地组成组,但我也违背了我已经享受的每个文件的一级清晰度.

您以何种方式使用嵌套类来使代码更易于管理,更易读,更高效?

Eri*_*ert 30

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

嵌套类无用的论点也是私有方法无用的参数:私有方法在类之外可能有用,因此你必须将它作为内部方法.内部方法在程序集之外可能很有用,因此您可以将其公之于众.因此,所有方法都应公开.如果你认为这是一个不好的论点,那么你为类而不是方法创建相同的参数有什么不同?

我一直在创建嵌套类,因为我经常处于需要将函数封装在一个在类之外没有意义的帮助器的位置,并且可以使用外部类的私有实现细节.例如,我编写编译器.我最近编写了一个类SemanticAnalyzer,它对解析树进行语义分析.其嵌套类之一是LocalScopeBuilder.在什么情况下,我需要建立一个本地范围的时候,我分析解析树的语义?决不.该类完全是语义分析器的实现细节.我计划添加更多嵌套类,其名称如NullableArithmeticAnalyzer和OverloadResolutionAnalyzer在类之外也没用,但我想在这些特定类中封装语言规则.

人们还使用嵌套类来构建迭代器或比较器之类的东西 - 在类之外没有意义并且通过众所周知的接口公开的东西.

我经常使用的模式是拥有扩展其外部类的私有嵌套类:

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

等等.嵌套类与工厂模式非常吻合.这里BankAccount是各种类型银行账户的工厂,所有这些都可以使用BankAccount的私人实施细节.但是没有第三方可以自己创建扩展BankAccount类型的EvilBankAccount.

  • 我认为我从未意识到嵌套类的价值的一个原因是,正如Henk在这里指出的那样,它本身并不是*嵌套类*,而是*私有嵌套类*.例如,您在答案中使用的所有示例都是*私有嵌套类*.因此,在阅读了上述问题的所有答案之后,我现在可以为私有嵌套类命名一些好的用例,但是对于公共,内部或公共内部嵌套类都没有. (3认同)
  • @Edward:实际上,框架设计指南建议公共嵌套类是个坏主意.合法但不好的风格.有点像公共领域.您想要公共嵌套类的情况很少见. (2认同)

JSB*_*ոգչ 11

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

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


Sky*_*ers 7

私人助手类就是一个很好的例子.

例如,后台线程的状态对象.揭露这些类型没有令人信服的理由.将它们定义为私有嵌套类型似乎是一种处理案例的非常简洁的方法.

  • 对.我使用私有嵌套类型的最常见方式是处理表单中的状态转换.这样做的好处是,状态可以访问和修改表单控件,而不必将它们公开/内部,并且它保持实际的状态转换细节与主表单代码分开. (6认同)

Jou*_*aas 6

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

我认为这是有道理的,因为如果没有其他人会使用它,为什么要为它创建一个外部类?它只是没有意义.

对于每个文件的一个类,您可以使用partial关键字创建部分类,这是我通常所做的.

  • +1从来没有想过为嵌套类使用partial,有趣 (2认同)

dlr*_*as2 6

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


Hen*_*man 5

"私有嵌套类"非常有用

请注意该句中的私密性.不建议使用公共嵌套类型.

就像大多数答案已经注意到的那样:每个类本身都是一个小软件项目.有时候需要招募助手类.但这不是一个值得努力的东西,你仍然不希望课程变得太大或太复杂.


Dan*_*ant 5

我发现一些非常方便的情况:

  1. 管理复杂的私有状态,例如Interpolator类使用的InterpolationTriangle。Interpolator的用户不需要知道它是使用Delauney三角测量实现的,当然也不需要知道三角形,因此数据结构是一个私有的嵌套类。

  2. 就像其他人提到的那样,您可以通过接口公开类使用的数据,而无需透露类的完整实现。嵌套类还可以访问外部类的私有状态,这使您可以编写紧密耦合的代码,而不必在公共(甚至内部在程序集的其余部分)公开这种紧密耦合。

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

  • +1关于穷人的多重继承,您的第三点很深,值得尝试 (2认同)

Jam*_*art 5

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

我还没有看到的一点是您对每个文件一个类的担忧的答案。您可以通过使外部类部分化并将内部类定义移动到单独的文件来解决此问题。

外部类.cs:

namespace MyNameSpace
{
    public partial class OuterClass
    {
        // main class members here
        // can use inner class
    }
}
Run Code Online (Sandbox Code Playgroud)

OuterClass.Inner.cs:

namespace MyNameSpace
{
    public partial class OuterClass
    {
        private class Inner
        {
            // inner class members here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以利用 Visual Studio 的项目嵌套使 OuterClass.Inner.cs 成为 OuterClass.cs 的“子级”,以避免使您的解决方案资源管理器混乱。