【问题标题】:Private inner classes in C# - why aren't they used more often?C# 中的私有内部类 - 为什么不经常使用它们?
【发布时间】:2009-01-17 22:41:25
【问题描述】:

我对 C# 比较陌生,每次开始从事 C# 项目时(我只从事过 C# 中几乎成熟的项目),我想知道为什么没有内部类?

也许我不明白他们的目标。对我来说,内部类——至少是私有内部类——看起来很像 Pascal / Modula-2 / Ada 中的“内部过程”:它们允许将主类分解成更小的部分,以便于理解。

示例:这是大多数时候看到的内容:

public class ClassA
{
   public MethodA()
   {
      <some code>
      myObjectClassB.DoSomething(); // ClassB is only used by ClassA
      <some code>
   }
}

public class ClassB
{
   public DoSomething()
   {
   }
}

由于 ClassB 将仅由 ClassA 使用(至少一段时间),我的猜测是这段代码会更好地表达如下:

   public class ClassA
   {
      public MethodA()
      {
         <some code>
         myObjectClassB.DoSomething(); // Class B is only usable by ClassA
         <some code>
      }

      private class ClassB
      {
         public DoSomething()
         {
         }
      }
   }

我很高兴收到您关于这个主题的消息 - 我说的对吗?

【问题讨论】:

  • 另请注意,嵌套类中不能有扩展方法..

标签: c# scope inner-classes


【解决方案1】:

嵌套类(最好避免使用“内部”一词,因为 C# 中的嵌套类与 Java 中的内部类有些不同)确实非常有用。

一种没有被提及的模式是“更好的枚举”模式——它甚至比 Java 中的更灵活:

public abstract class MyCleverEnum
{
    public static readonly MyCleverEnum First = new FirstCleverEnum();
    public static readonly MyCleverEnum Second = new SecondCleverEnum();

    // Can only be called by this type *and nested types*
    private MyCleverEnum()
    {
    }

    public abstract void SomeMethod();
    public abstract void AnotherMethod();

    private class FirstCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // First-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // First-specific behaviour here
        }
    }

    private class SecondCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // Second-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // Second-specific behaviour here
        }
    }
}

我们可以通过一些语言支持来自动完成其中的一些工作 - 还有很多我没有在这里展示的选项,比如实际上不对所有值使用嵌套类,或者对所有值使用相同的嵌套类多个值,但给它们不同的构造函数参数。但基本上,嵌套类可以调用私有构造函数这一事实提供了很大的力量。

【讨论】:

  • 非常聪明!但我永远不会使用它。软件书籍作者和他们的读者(!)通常是聪明的人。他们想到了很多光明的事情,这很酷。但是软件维护者是没有读过 Gamma/Skeet 的普通人。我的客人:它越聪明,它就越难维护......
  • 在它成为公认的模式之前,这是真的。就像“while ((line = streamReader.ReadLine()) != null)”一开始看起来很糟糕——在一段时间条件下会产生副作用!但是当它是惯用语时,你就会摆脱那种气味并欣赏它的简洁性。
  • @Sylvain:我认为它就像 LINQ - 当您习惯它时,它增加了 可维护性,但乍一看看起来很奇怪。但我同意这在 C# 中还不是一种常见的模式:(
  • @Jon,谢谢!我想我现在明白了。 MyCleverEnum 既是枚举成员的持有者,又是每个枚举成员的接口,因此比其他解决方案更简洁。嵌入类的使用确保支持类对类外部隐藏。私有构造函数使该类在类外部表现得像一个静态/单例类,但在类内部却像一个抽象基类。
  • @supercat,您可以在文件 using FirstCleverEnum = MyCleverEnum.FirstCleverEnum 的顶部放置一个 using 指令。这可以缓解问题,但没有办法“导出”这个别名。
【解决方案2】:

Framework Design Guidelines 拥有迄今为止我发现的使用嵌套类的最佳规则。

这是一个简短的摘要列表:

  1. 当类型和嵌套类型之间的关系需要成员可访问性语义时,请使用嵌套类型。

  2. 使用公共嵌套类型作为逻辑组结构

  3. 避免使用公开的嵌套类型。

  4. 如果类型可能在包含类型之外被引用,请使用嵌套类型。

  5. 如果需要由客户端代码实例化,请使用嵌套类型。

  6. 将嵌套类型定义为接口的成员。

【讨论】:

  • 其中一些是相当明显的(例如 4 和 5)。但是您能否指出推荐其他规则的原因?
  • @PeterBagnall 只是我,还是第 6 个与接受的答案相矛盾?
  • @jungle_mole 实现公共接口的嵌套类型很好也很常见。嵌套类型永远不应该公开。
  • @Erick 是的。我刚刚在脑海中交换了两个“设计”的两个部分。第 6 次的原因很明显。我什至在想什么
【解决方案3】:

您应该限制每个类的职责,以使每个类都保持简单、可测试和可重用。私有内部类与此相反。它们增加了外部类的复杂性,它们不可测试且不可重用。

【讨论】:

  • 简单、可测试和可重用非常棒。但是封装呢?不应该在外面看到的东西,为什么要公开呢?在我的书中,内部类可以使整个事情变得更简单。而且它们是可测试的(带有relexion)!
  • 我会选择封装作为反对内部类的参数。内部类可以访问其外部类的私有成员!
  • 你的权利!有一个内部类在它和外部类之间添加了某种耦合 - 我一开始没有看到它 - 抱歉。谢谢!
  • 我看到程序员一直使用像元组这样的数据结构而不是私有类。我肯定会争辩说,私有类会导致代码更易于阅读且不易出错。认为它违反封装是不正确的。私有类并没有违反封装。它包含在一个类中,并且应该并且确实拥有外部类的任何其他成员的所有权利。
  • 与所有事情一样,这取决于。在这种情况下,我认为这取决于嵌套类的细节。例如,如果您在父类中创建 dto(例如,保持方法签名干净),则无需测试。它与创建私有元组 imo 没有任何不同,只是更清楚。但是,如果您创建了一个具有功能的丰富嵌套类,那么您将度过一段糟糕的时光。
【解决方案4】:

就我个人而言,如果我需要创建可能需要方法的对象的进程内集合,我只会创建私有内部类。

否则,项目中的其他开发人员在实际找到这些类时可能会感到困惑,因为他们不太清楚自己在哪里。

【讨论】:

  • 但是由于它们是私有类,其他开发人员不应该知道它们,当然,除非他们必须维护外部类。当然,这可能是人们不知道私有内部类的问题。谢谢你的回答!
  • 如果这让我的开发人员感到困惑,我会找新的开发人员。
猜你喜欢
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 2011-07-15
  • 2020-03-06
  • 1970-01-01
相关资源
最近更新 更多