为什么/什么时候应该在 .net 中使用嵌套类? 或者你不应该吗?
在 Kathleen Dollard 2008 年的博客文章,她提出了在 .net 中使用嵌套类的一个有趣的原因。 然而,她还提到 FxCop 不喜欢嵌套类。 我假设编写 FxCop 规则的人并不愚蠢,所以这个立场背后一定有推理,但我还没有找到它。
In Kathleen Dollard's 2008 blog post, she presents an interesting reason to use nested classes in .net. However, she also mentions that FxCop doesn't like nested classes. I'm assuming that the people writing FxCop rules aren't stupid, so there must be reasoning behind that position, but I haven't been able to find it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
基于我对这个概念的理解
当类在概念上彼此相关时,我们可以使用此功能。
我的意思是,其中一些是我们业务中完整的一个项目,就像 DDD 世界中存在的实体一样,有助于聚合根对象完成其业务逻辑。
为了澄清这一点,我将通过一个示例来展示这一点:
假设我们有两个类,例如 Order 和 OrderItem。
在订单类中,我们将管理所有订单项,在订单项中我们保存有关单个订单的数据
为了澄清起见,您可以查看以下课程:
Base on my understanding of this concept
we could use this feature when classes are related to each other conceptually.
I mean some of them are complete one Item in our business like entities that exist in the DDD world that help to an aggregate root object to complete its business logic.
In order to clarify I'm going to show this via an example:
Imagine that we have two classes like Order and OrderItem.
In order class, we are going to manage all orderItems and in OrderItem we are holding data about a single order
for clarification, you can see below classes:
对于这种情况是的:
yes for this case:
请记住,您需要测试嵌套类。 如果它是私有的,您将无法单独测试它。
不过,您可以将其设置为内部,与
InternalsVisibleTo
属性结合使用。 然而,这与仅出于测试目的而将私有字段设置为内部相同,我认为这是糟糕的自我文档。因此,您可能只想实现复杂度较低的私有嵌套类。
Bear in mind that you'll need to test the nested class. If it is private, you won't be able to test it in isolation.
You could make it internal, though, in conjunction with the
InternalsVisibleTo
attribute. However, this would be the same as making a private field internal only for testing purposes, which I consider bad self-documentation.So, you may want to only implement private nested classes involving low complexity.
正如 nawfal 提到的抽象工厂模式的实现,可以扩展该代码来实现 类簇模式基于抽象工厂模式。
As nawfal mentioned implementation of Abstract Factory pattern, that code can be axtended to achieve Class Clusters pattern which is based on Abstract Factory pattern.
我喜欢嵌套单个类特有的异常,即。 那些从未从其他地方扔过的东西。
例如:
这有助于保持项目文件整洁,并且不会充满一百个粗短的小异常类。
I like to nest exceptions that are unique to a single class, ie. ones that are never thrown from any other place.
For example:
This helps keep your project files tidy and not full of a hundred stubby little exception classes.
嵌套类可以用于以下需求:
The nested classes can be used for following needs:
嵌套类的另一个尚未提及的用途是泛型类型的隔离。 例如,假设想要拥有一些静态类的通用系列,这些静态类可以采用具有不同数量参数的方法以及其中一些参数的值,并生成具有较少参数的委托。 例如,人们希望有一个静态方法,它可以采用
Action
并生成String
,该方法将调用提供的操作将 3.5 作为double
传递; 人们可能还希望有一个静态方法,它可以接受一个Action
并产生一个Action
,传递7< /code> 作为
int
,5.3
作为double
。 使用泛型嵌套类,可以安排方法调用类似于:或者,因为每个表达式中的后一个类型可以推断,即使前一个类型不能:
使用嵌套泛型类型可以判断哪些委托适用于总体类型描述的哪些部分。
Another use not yet mentioned for nested classes is the segregation of generic types. For example, suppose one wants to have some generic families of static classes that can take methods with various numbers of parameters, along with values for some of those parameters, and generate delegates with fewer parameters. For example, one wishes to have a static method which can take an
Action<string, int, double>
and yield aString<string, int>
which will call the supplied action passing 3.5 as thedouble
; one may also wish to have a static method which can take an anAction<string, int, double>
and yield anAction<string>
, passing7
as theint
and5.3
as thedouble
. Using generic nested classes, one can arrange to have the method invocations be something like:or, because the latter types in each expression can be inferred even though the former ones can't:
Using the nested generic types makes it possible to tell which delegates are applicable to which parts of the overall type description.
如果我理解凯瑟琳的文章正确的话,她建议使用嵌套类来编写 SomeEntity.Collection 而不是 EntityCollection< 某个实体>。 在我看来,这是一种有争议的方式来节省你的打字时间。 我非常确定在现实世界中应用程序集合在实现上会有一些差异,因此无论如何您都需要创建单独的类。 我认为使用类名来限制其他类的范围不是一个好主意。 它污染了智能感知并加强了类之间的依赖关系。 使用命名空间是控制类范围的标准方法。 然而,我发现像 @hazzen 评论中那样使用嵌套类是可以接受的,除非你有大量的嵌套类,这是糟糕设计的标志。
If I understand Katheleen's article right, she proposes to use nested class to be able to write SomeEntity.Collection instead of EntityCollection< SomeEntity>. In my opinion it's controversial way to save you some typing. I'm pretty sure that in real world application collections will have some difference in implementations, so you will need to create separate class anyway. I think that using class name to limit other class scope is not a good idea. It pollutes intellisense and strengthen dependencies between classes. Using namespaces is a standard way to control classes scope. However I find that usage of nested classes like in @hazzen comment is acceptable unless you have tons of nested classes which is a sign of bad design.
我经常使用嵌套类来隐藏实现细节。 Eric Lippert 的回答中的一个示例:
使用泛型时,这种模式会变得更好。 请参阅这个问题适合两个人很酷的例子。 所以我最终写的
是
Also I can have a generic list of Equality但不是
EqualityComparer
,这是
不可能的。 这就是嵌套类继承父类的好处。
另一种情况(具有相同性质 - 隐藏实现)是当您想让类的成员(字段、属性等)只能由单个类访问时:
I often use nested classes to hide implementation detail. An example from Eric Lippert's answer here:
This pattern becomes even better with use of generics. See this question for two cool examples. So I end up writing
instead of
Also I can have a generic list of
Equality<Person>
but notEqualityComparer<Person, int>
where as
is not possible. That's the benefit of nested class inheriting from parent class.
Another case (of the same nature - hiding implementation) is when you want to make a class's members (fields, properties etc) accessible only for a single class:
来自 Sun 的 Java 教程:
为什么使用嵌套类?
使用嵌套类有几个令人信服的理由,其中包括:
类的逻辑分组——如果一个类仅对另一个类有用,那么将其嵌入到该类中并将两个类放在一起是合乎逻辑的。 嵌套这样的“帮助类”使得它们的包更加精简。
增强封装性 - 考虑两个顶级类 A 和 B,其中 B 需要访问 A 的成员,否则这些成员将被声明为私有。 通过将类 B 隐藏在类 A 中,可以将 A 的成员声明为私有,并且 B 可以访问它们。 另外,B本身可以对外界隐藏。<- 这不适用于C#的嵌套类实现,这只适用于Java。更具可读性、可维护性的代码——在顶级类中嵌套小类使代码更接近其使用位置。
From Sun's Java Tutorial:
Why Use Nested Classes?
There are several compelling reasons for using nested classes, among them:
Logical grouping of classes—If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.
Increased encapsulation—Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.<- This doesn't apply to C#'s implementation of nested classes, this only applies to Java.More readable, maintainable code—Nesting small classes within top-level classes places the code closer to where it is used.
完全惰性且线程安全的单例模式
源:https://csharpin深度.com/Articles/Singleton
Fully Lazy and thread-safe singleton pattern
source: https://csharpindepth.com/Articles/Singleton
这取决于用途。 我很少使用公共嵌套类,但一直使用私有嵌套类。 私有嵌套类可用于仅在父对象内部使用的子对象。 例如,HashTable 类包含一个私有 Entry 对象以仅在内部存储数据。
如果该类旨在由调用者(外部)使用,我通常喜欢将其作为单独的独立类。
It depends on the usage. I rarely would ever use a Public nested class but use Private nested classes all of the time. A private nested class can be used for a sub-object that is intended to be used only inside the parent. An example of this would be if a HashTable class contains a private Entry object to store data internally only.
If the class is meant to be used by the caller (externally), I generally like making it a separate standalone class.
除了上面列出的其他原因之外,我还能想到的另一个原因不仅是使用嵌套类,而且实际上是公共嵌套类。 对于那些使用共享相同泛型类型参数的多个泛型类的人来说,声明泛型命名空间的能力将非常有用。 不幸的是,.Net(或至少是 C#)不支持通用命名空间的想法。 因此,为了实现相同的目标,我们可以使用泛型类来实现相同的目标。 以与逻辑实体相关的以下示例类为例:
我们可以通过使用通用命名空间(通过嵌套类实现)来简化这些类的签名:
然后,通过使用 Erik van Brakel 在早期评论中建议的部分类,您可以将类分成单独的嵌套文件。 我建议使用像 NestIn 这样的 Visual Studio 扩展来支持嵌套部分类文件。 这允许“命名空间”类文件也可用于以类似文件夹的方式组织嵌套类文件。
例如:
Entity.cs
Entity.BaseDataObject.cs
Entity.BaseDataObjectList.cs
Entity.IBaseBusiness.cs
Entity.IBaseDataAccess.cs
Visual Studio 解决方案资源管理器中的文件将按如下方式组织:
您将实现通用命名空间,如以下:
User.cs
User.DataObject.cs
User.DataObjectList.cs
User.IBusiness.cs
User.IDataAccess.cs
文件将在解决方案资源管理器中组织如下:
上面是使用外部类作为的简单示例通用命名空间。 我过去构建过包含 9 个或更多类型参数的“通用命名空间”。 必须使这些类型参数在所有需要知道类型参数的九种类型之间保持同步是乏味的,尤其是在添加新参数时。 通用命名空间的使用使代码更易于管理和可读。
In addition to the other reasons listed above, there is one more reason that I can think of not only to use nested classes, but in fact public nested classes. For those who work with multiple generic classes that share the same generic type parameters, the ability to declare a generic namespace would be extremely useful. Unfortunately, .Net (or at least C#) does not support the idea of generic namespaces. So in order to accomplish the same goal, we can use generic classes to fulfill the same goal. Take the following example classes related to a logical entity:
We can simplify the signatures of these classes by using a generic namespace (implemented via nested classes):
Then, through the use of partial classes as suggested by Erik van Brakel in an earlier comment, you can separate the classes into separate nested files. I recommend using a Visual Studio extension like NestIn to support nesting the partial class files. This allows the "namespace" class files to also be used to organize the nested class files in a folder like way.
For example:
Entity.cs
Entity.BaseDataObject.cs
Entity.BaseDataObjectList.cs
Entity.IBaseBusiness.cs
Entity.IBaseDataAccess.cs
The files in the visual studio solution explorer would then be organized as such:
And you would implement the generic namespace like the following:
User.cs
User.DataObject.cs
User.DataObjectList.cs
User.IBusiness.cs
User.IDataAccess.cs
And the files would be organized in the solution explorer as follows:
The above is a simple example of using an outer class as a generic namespace. I've built "generic namespaces" containing 9 or more type parameters in the past. Having to keep those type parameters synchronized across the nine types that all needed to know the type parameters was tedious, especially when adding a new parameter. The use of generic namespaces makes that code far more manageable and readable.
当您嵌套的类仅对封闭类有用时,请使用嵌套类。 例如,嵌套类允许您编写类似(简化的)的内容:
您可以在一个地方对您的类进行完整的定义,您不必跳过任何 PIMPL 环来定义您的类如何工作以及外部世界不需要看到你的任何实现。
如果 TreeNode 类是外部的,您要么必须将所有字段设为 public ,要么创建一堆 get/set 方法才能使用它。 外界会有另一个类污染他们的智能感知。
Use a nested class when the class you are nesting is only useful to the enclosing class. For instance, nested classes allow you to write something like (simplified):
You can make a complete definition of your class in one place, you don't have to jump through any PIMPL hoops to define how your class works, and the outside world doesn't need to see anything of your implementation.
If the TreeNode class was external, you would either have to make all the fields
public
or make a bunch ofget/set
methods to use it. The outside world would have another class polluting their intellisense.