在this stackoverflow answer中,一位评论者提到“私有嵌套类”非常有用所以我在articles such as this one中阅读了这些内容,这些内容倾向于解释嵌套类如何运行技术,但为什么你会使用它们。
我想我会为属于更大类的小帮助类使用私有嵌套类,但是我经常需要来自另一个类的辅助类,所以我只需要额外的努力(1)使嵌套类非嵌套或(2)使其公开,然后使用外部类前缀访问它,这似乎是额外的工作,没有任何附加值,使嵌套类在第一名。因此,总的来说我真的没有看到嵌套类的用例,除了可能让类更加有条理地组成组,但我也反对 one-class-我已经开始享受每个文件的清晰度。
您在哪些方面使用嵌套类来使代码更易于管理,更易读,更有效?
答案 0 :(得分:28)
你已经回答了自己的问题。当你需要一个在类外没有意义的辅助类时,使用嵌套类;特别是当嵌套类可以使用外部类的私有实现细节时。
嵌套类无用的论点也是私有方法无用的参数:私有方法在类之外可能有用,因此你必须将其设置为内部方法。内部方法在程序集之外可能很有用,因此您可以将其公之于众。因此,所有方法都应公开。如果您认为这是一个不好的论点,那么您为类而不是方法创建相同的参数有什么不同?
我一直在创建嵌套类,因为我经常处于需要将函数封装在一个在类之外没有意义的帮助器的位置,并且可以使用外部类的私有实现细节。例如,我编写编译器。我最近编写了一个类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 { ... }
等等。嵌套类与工厂模式非常吻合。这里BankAccount是各种类型银行账户的工厂,所有这些都可以使用BankAccount的私人实施细节。但是没有第三方可以自己创建扩展BankAccount的EvilBankAccount类型。
答案 1 :(得分: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();
}
}
答案 2 :(得分:7)
私人助手类就是一个很好的例子。
例如,后台线程的状态对象。揭露这些类型没有令人信服的理由。将它们定义为私有嵌套类型似乎是处理这种情况的一种非常简洁的方法。
答案 3 :(得分:6)
当两个绑定值(如哈希表中)在内部不够用时,我使用它们,但外部足够。然后我创建一个嵌套类,其中包含我需要存储的属性,并且只通过方法公开其中的一些。
我认为这是有道理的,因为如果没有其他人会使用它,为什么要为它创建一个外部类?它只是没有意义。
对于每个文件一个类,您可以使用partial
关键字创建部分类,这是我通常所做的。
答案 4 :(得分:6)
我最近遇到的一个引人注目的例子是许多数据结构的Node
类。例如,Quadtree
需要知道它如何将数据存储在其节点中,但代码的其他部分不应该关注。
答案 5 :(得分:5)
“私有嵌套类”非常有用
请注意该句中的私人。不建议使用公共嵌套类型。
与大多数答案一样,已经注意到:每个类本身都是一个小软件项目。有时候需要招募助手类。但这不是一个值得努力的东西,你仍然不希望课程变得太大或太复杂。
答案 6 :(得分:4)
我发现了一些他们非常方便的案例:
复杂私有状态的管理,例如Interpolator类使用的InterpolationTriangle。 Interpolator的用户不需要知道它是使用Delauney三角测量实现的,当然也不需要知道三角形,因此数据结构是一个私有嵌套类。
正如其他人所提到的,您可以使用接口公开类使用的数据,而不会泄露类的完整实现。嵌套类还可以访问外部类的私有状态,这允许您编写紧密耦合的代码,而不会公开(或甚至内部到组件的其余部分)紧密耦合。
我遇到过一些框架需要从某个基类派生类(例如WPF中的DependencyObject)的情况,但是你希望你的类继承自不同的基类。通过使用从框架基类继承的私有嵌套类,可以与框架进行交互操作。因为嵌套类可以访问私有状态(你只是在创建它时将它传递给父's'),你基本上可以使用它来通过组合实现穷人的多重继承。
答案 7 :(得分:3)
使用此技术的一种非常常见的模式是在类从其属性或方法之一返回接口或基类类型的情况下,但具体类型是私有嵌套类。请考虑以下示例。
public class MyCollection : IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyEnumerator();
}
private class MyEnumerator
{
}
}
答案 8 :(得分:2)
我通常在某些情况下需要SRP(单一责任委托人)的组合时这样做。
“好吧,如果SRP是你的目标,为什么不将它们分成不同的类?”你将在80%的时间内完成这项任务,但是你创建的类对于无法使用的情况怎么办?外面的世界?您不希望只使用的类会使程序集的API混乱。
“嗯,这不是internal
的用途吗?”当然。约占这些案件的80%。但是那些必须访问或修改公共类状态的内部类呢?例如,该类被分解为一个或多个内部类以满足您的SRP条纹?您必须将这些internal
类标记的所有方法和属性标记为internal
。
“这有什么问题?”没什么。约占这些案件的80%。当然,现在您使用的方法/属性使您的类的内部接口混乱,这些方法/属性仅用于您之前创建的类。现在你必须担心团队中其他人编写内部代码不会以你没想到的方式使用这些方法来搞乱你的状态。
内部类可以修改定义它们的任何类型实例的状态。因此,如果不向类型定义添加成员,内部类可以根据需要处理它们。其中,在100个中的大约14个案例中,最好的办法是保持您的类型清洁,您的代码可靠/可维护,以及您的职责是单一的。
答案 9 :(得分:2)
我认为其他人已经很好地介绍了公共和私有嵌套类的用例。
我没有看到的一点是你对每个文件一类的关注。您可以通过使外部类成为局部来解决此问题,并将内部类定义移动到单独的文件中。
OuterClass.cs:
namespace MyNameSpace
{
public partial class OuterClass
{
// main class members here
// can use inner class
}
}
OuterClass.Inner.cs:
namespace MyNameSpace
{
public partial class OuterClass
{
private class Inner
{
// inner class members here
}
}
}
您甚至可以使用Visual Studio的项嵌套来使OuterClass.Inner.cs成为OuterClass.cs的“子”,以避免混乱您的解决方案资源管理器。
答案 10 :(得分:1)
作为一个例子,它们非常适合singleton pattern.
的实现我有几个地方也在使用它们来“添加”价值。我有一个多选组合框,我的内部类也存储了复选框的状态和数据项。世界上没有必要知道/使用这个内部课程。
答案 11 :(得分:0)
私有匿名嵌套类对GUI中的事件处理程序至关重要。
如果某个类不是另一个类导出的API的一部分,则必须将其设为私有。否则你暴露的比你想要的多。 “百万美元的臭虫”就是一个例子。大多数程序员都对此过于懈怠。
彼得
答案 12 :(得分:0)
这个问题被标记为C#所以我不确定这是有意义的,但是在COM中你可以使用内部类来实现C ++类实现多个COM接口时的接口...基本上你用它来组合而不是多个-inheritance。
此外,在MFC和其他技术中,你可能需要你的控件/对话框来设置一个drop-target类,除了作为嵌套类之外没什么意义。
答案 13 :(得分:0)
如果对象需要返回有关其状态的一些抽象信息,则私有嵌套类可能是合适的。例如,如果Fnord支持“保存上下文”和“恢复上下文”方法,则使用“保存上下文”函数返回Fnord.SavedContext类型的对象可能很有用。类型访问规则并不总是最有帮助的;例如,似乎很难允许Fnord访问Fnord.SavedContext的属性和方法,而不会使外部人员看到这些属性和方法。另一方面,可以让Fnord.CreateSaveContext创建一个以Fnord为参数的New Fnord.SaveContext(因为Fnord.SaveContext可以访问Fnord的内部),而Fnord.LoadContextFrom()可以调用Fnord.SaveContext.RestoreContextTo ()。