简体   繁体   English

在C#中的另一个类内声明的类

[英]Class declared inside of another class in C#

I am working on some legacy code and have come across something that I'm not sure of. 我正在研究一些遗留代码,并且遇到了一些我不确定的问题。 We have a class y that is declared inside of another class x . 我们有一个class y是另一个的内部声明class x Class y is only ever used inside of class x but my question is why wouldn't you create a separate class file and put class y in there instead of declaring it inside of class x ? Class y只在class x使用,但我的问题是为什么你不创建一个单独的类文件并将class y放在那里而不是在class x中声明它? Isn't this violating OOP's or is it just a matter of style since it is only ever used inside of this class. 这不是违反OOP的,或者只是风格问题,因为它只在本课程中使用过。 I'm refactoring some of this code and my first reaction would be to separate class y out into it's own file. 我正在重构一些代码,我的第一反应是将class y分成它自己的文件。

namespace Library
{
   public class x
   {
      // methods, properties, local members of class x

      class y
      {
         // methods, properties, local members of class y
      }
   }
}

You create an inner class because it is only ever used within the scope of class x and it logically fits in the factoring/architecture of class x. 您创建了一个内部类,因为它只在类x的范围内使用,并且它在逻辑上适合于类x的因子/体系结构。

Class y might also be privy to implementation details of class x that are not meant to be known to the public. 类y也可能知道x类的实现细节,这些细节并不是公众所知的。

This has permissions implications. 这具有权限含义。 A top-level "class y" would be "internal" - however, here "y" is private to "x". 顶级“类y”将是“内部” - 但是,这里“y”对“x”是私有的。 This approach is helpful for implementation details (for example cache rows etc). 此方法有助于实现细节(例如缓存行等)。 Likewise, y has access to all private state of x . 同样, y可以访问x所有私有状态。

There are also implications with generics; 仿制药也有其含义; x<T>.y is generic "of T", inherited from the outer class. x<T>.y是通用的“T”,继承自外部类。 You can see this here, where Bar has full use of T - and note that any static fields of Bar are scoped per- T . 你可以在这里看到这里, Bar充分利用了T - 并注意Bar任何静态字段都是以T为范围的。

class Foo<T> {
    void Test(T value) {
        Bar bar = new Bar();
        bar.Value = value;
    }
    class Bar {
        public T Value { get; set; }
    }
}

Often people incorrectly think they need to define Bar as Bar<T> - this is now (effectively) doubly generic - ie Foo<TOld, T> - where TOld is the (now unavailable) T from Foo<T> . 通常人们错误地认为他们需要将Bar定义为Bar<T> - 这现在(有效地)是双重通用的 - 即Foo<TOld, T> - 其中TOld是来自Foo<T>的(现在不可用) T So don't do that! 所以不要这样做! Or if you want it to be doubly-generic, pick different names. 或者,如果您希望它是双重通用的,请选择不同的名称。 Fortunately, the compiler warns you about this... 幸运的是,编译器警告你这个......

This code is fine for the exact reason that you have given - "class y is only ever used inside of class x". 这个代码很好,因为你给出的确切原因 - “类y只在类x中使用过”。 Those are nested types and one of the guidelines for using them is that nested types should be tightly coupled to their declaring type and must not be useful as a general purpose type. 这些是嵌套类型 ,使用它们的一个原则是嵌套类型应该与它们的声明类型紧密耦合,并且不能用作通用类型。 That way the nested class is inacessible to other classes, but still allows you to follow object oriented principles. 这样,嵌套类对其他类来说是不可能的,但仍然允许您遵循面向对象的原则。

I think it's ok, as long as the contained class is only used as utility. 我认为没关系,只要包含的类仅用作实用程序。 I use this sort of construct for example to define complex return types for private methods. 我使用这种构造来为私有方法定义复杂的返回类型。

I just went through code that I am updating (and I originally wrote) and removed all nested classes. 我刚刚浏览了我正在更新的代码(我最初写的)并删除了所有嵌套类。 Unfortunately, I originally used the nested class outside of the class it was defined in. Moving nested classes out made a huge difference to me because I originally had bad design. 不幸的是,我最初在它定义的类之外使用了嵌套类。移动嵌套类对我来说有很大的不同,因为我最初设计不好。

If Y is only used in X and will never be used outside of X, I'd say keep it there 如果Y仅用于X并且永远不会在X之外使用,我会说保留在那里

Let me give you an example of the use of nested classes that might clarify when this kind of architecture is appropriate. 让我举一个使用嵌套类的例子,这些嵌套类可能会澄清何时这种架构是合适的。 I recently needed to generate an HTML table by pulling selected columns from a data table and "pivoting" them so that rows become columns and vice versa. 我最近需要通过从数据表中提取所选列并“旋转”它们来生成HTML表,以便行成为列,反之亦然。 In my case, there were two essential operations: pivoting the data and generating some rather complex output (I was not just showing the data: each data column/table row was subject to operations for extracting title, generating image tags, setting up links, etc. thus using a SQL Pivot wasn't really right either). 在我的例子中,有两个基本操作:转动数据并生成一些相当复杂的输出(我不只是显示数据:每个数据列/表行都受制于提取标题,生成图像标签,设置链接的操作,因此,使用SQL Pivot也不是正确的。)

After an initial attempt to create one class to do the whole thing, I recognized that much of the data/methods fell into three distinct partitions: header processing, row processing, and pivoting. 在最初尝试创建一个类来执行整个操作之后,我意识到许多数据/方法分为三个不同的分区:头处理,行处理和旋转。 Thus, I decided that a better approach would be to encapsulate the logic for "header" and "row" into separate, nested classes. 因此,我认为更好的方法是将“header”和“row”的逻辑封装到单独的嵌套类中。 This allowed me to separate the data held by each row and program the pivot operations very cleanly (calling a separate row object for each column in your data table). 这允许我将每行保存的数据分开,并非常干净地编程数据透视操作(为数据表中的每一列调用一个单独的行对象)。 At the end of the pivot operations, I generated output by calling the header object and then each row object in turn to generate its output back to the main class. 在数据透视操作结束时,我通过调用头对象生成输出,然后依次调用每个行对象以将其输出生成回主类。

Separate classes weren't appropriate because A) the nested classes did need some data from the master class and B) the processing was very specific and not useful elsewhere. 单独的类是不合适的,因为A)嵌套类确实需要来自主类的一些数据和B)处理非常具体,在其他地方没有用处。 Just programming one big class was simply messier due to confusion surrounding terms such as "column" and "row" which differed depending on whether you were talking about data or HTML output. 由于围绕“列”和“行”之类的术语混淆,根据您是在谈论数据还是HTML输出,编写一个大类只是简单的混乱。 Also, this was unusual work in that I was generating HTML in my business class so I wanted to pull apart the pure business logic from the UI generation. 此外,这是不寻常的工作,因为我在我的业务类中生成HTML,所以我想从UI生成中分离出纯粹的业务逻辑。 In the end, nested classes provided the perfect balance, then, of encapsulation and data sharing. 最后,嵌套类提供了封装和数据共享的完美平衡。

You could still refactor your class y into another file, but use a parial class. 你仍然可以将你的类y重构为另一个文件,但是使用一个parial类。 The benefit of this is that you still have one class per file and don't have the refactoring hassles of moving the declaration outside of class x. 这样做的好处是,每个文件仍然有一个类,并且没有在x类之外移动声明的重构麻烦。

eg you could have a code file: xycs which would look something like 例如,你可以有一个代码文件:xycs看起来像

partial class X
{
    class Y
    {
        //implementation goes here
    }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM