【问题标题】:What are the benefits to using a partial class as opposed to an abstract one?与抽象类相比,使用部分类有什么好处?
【发布时间】:2010-11-06 16:04:08
【问题描述】:

我一直在阅读 Programming Microsoft® Visual C#® 2008: The Language 以更好地理解 C# 以及可以用它做什么。我从 ASP.Net 的 Page 类中遇到了部分类。

在我看来,你可以用一个抽象类和一个被覆盖的类来做部分类所做的事情。显然,一个团队将通过抽象方法控制接口,但无论如何你都会相互依赖。如果目标是协作,那么源代码控制和其他工具就不能解决这个问题。

我只是错过了部分课程的重点。也有人可以提供真实世界的使用。

【问题讨论】:

    标签: c# class abstract-class partial-classes


    【解决方案1】:

    部分类与对象继承无关。部分类只是将定义类的源代码拆分为单独文件的一种方式(例如,当您在 Windows 窗体应用程序中创建新表单时会这样做 - 一个文件是“您的”代码,另一个文件是 .designer.cs包含VS2008为你管理的代码)。

    【讨论】:

    • 我知道它与继承无关,但是您可以做同样的事情,因为它是继承的一种副作用,您可以将代码拆分为单独的文件。不过,可能不如部分课程提供的那么好或干净。我只是想找到它们的用途。
    • 糟糕,抱歉。我在键盘上的速度太快了。所以最终设计器代码和你的代码最终会在同一个文件中?如果是这样的话,现在我看到了它的用途。但是除非我尝试做类似的事情,否则我可能永远不会使用它。
    • 他们做的事情与继承完全不同。一个使用示例是 Visual Studio。表单生成器生成一个带有设置控件的代码的部分类文件。用户代码位于单独的文件中。编译后,这些文件合并为一个类。 Partial 类的真正杀手级应用程序是生成部分但不完全由生成的代码组成的类。你可以用(例如)一个 O/R 映射器做类似的事情。
    • 是的,编译器将这些单独的文件视为一个类定义(我猜你可以想象它在编译之前将它们合并到内存中的一个文件中)。然而,抽象类有点像其他类的“模板”,因为它的定义是完整的,但实现不是。但是,如果您希望将类定义分布在多个文件中,抽象类也可以实现为部分类。
    【解决方案2】:

    一个很好的用法示例是生成部分类的一侧(例如 ORM)

    【讨论】:

    • IMO,这是部分类的唯一好用法。必须将单个类拆分为多个文件是一种异味。
    • IMO 这是部分类的不良用法之一。如果生成的类是抽象的,您可以覆盖行为、对设置器的验证等。使用 patial 类时,您会被生成方产生的方法/属性所困扰。
    【解决方案3】:

    部分类的好处在于您可以获取现有类并添加到它。现在这听起来很像继承,但是有很多继承不能做的事情,部分类可以做到。

    这里有一个关于为您生成的 Linq to SQL 类的想法。它们是自动生成的,这意味着您不应修改它们。没有分部类,就不能附加接口。 您可以创建一个新类并从 Linq to sql 类派生该类,但这实际上并没有为您带来任何好处,因为您无法使用接口将 linq to sql 类向上转换到您的类。

    【讨论】:

      【解决方案4】:

      部分类应仅限于与自动生成的代码一起使用,其中其他代码无法修改。将其用作继承或添加功能的替代品并不是最佳做法。

      如果你的班级很大,那它就已经错了。代码应该被重构为多个“真实”类而不是多个文件。大类一般表示该类做的事情太多,违反了 SRP(单一职责原则)。

      【讨论】:

        【解决方案5】:

        部分类现在在 ASP.Net 中大量使用,以允许两个源文件,即基于标记的 example.aspx 和基于代码的 example.aspx.cs,以便每个文件中定义的方法和变量对每个文件都是可见的。 在example.aspx中

        <custom:exampleControl id="exampleCntr" property="<%#getProperty()%>" />
        

        在example.aspx.cs中

        private object GetProperty(){ // called from aspx
            return DateTime.Now;
        }
        
        private void DoStuff(){
            ExampleControl c = exampleCntr; //exampleCntr is defined in aspx.
        }
        

        这种双向性质无法用抽象类重新创建。

        【讨论】:

          【解决方案6】:

          听起来你的问题是有什么区别

          partial class Foo
          {
            PART ONE
          }
          partial class Foo
          {
            PART TWO
          }
          

          astract class FooBase
          {
            PART ONE
          }
          partial class Foo : FooBase
          {
            PART TWO
          }
          

          虽然它们看起来有些相似,并且在某些情况下可以使用后一种构造来代替前者,但后一种风格至少存在两个问题:

          -1- FooBase 类型可能必须知道应该从它派生的具体类型的标识,并且始终使用该类型的变量,而不是 FooBase 类型的变量。这代表了这两种类型之间的一种令人不安的紧密耦合。

          -2- 如果Foo 类型是公开的,那么FooBase 类型也必须是公开的。即使FooBase的所有构造函数都是internal,外部代码也有可能定义派生自FooBase而不是Foo的类;构造此类类的实例会很困难,但并非不可能。

          如果派生类型可以扩展基类型的可见性,这些问题就不会太成问题;有人会将FooBase 视为“一次性”标识符,它恰好出现两次:一次在其声明中,一次在Foo 的声明行中,并认为每个FooBase 都是伪装的FooFooBase 不能在没有类型转换的情况下在 this 上使用 Foo 实例成员这一事实可能令人讨厌,但也可以鼓励代码的良好分区。但是,由于无法扩展基类型的可见性,因此抽象类的设计似乎很糟糕。

          【讨论】:

            【解决方案7】:

            部分类的目的是允许一个类的定义跨越多个文件。这可以提高代码的可维护性和分离性。

            【讨论】:

              【解决方案8】:

              我们使用部分类来拆分更大的类。这样就更容易使用 Sourcesafe 检出部分代码。这限制了四个开发人员需要访问同一个文件的情况。

              【讨论】:

              • 虽然我知道部分类,但我自己实际上从未使用过它们(除了自动生成的类)。对于将哪种方法放入哪种文件,是否有团队内部规则?有命名约定吗?我一直有点担心在广泛使用部分类时会增加“查找特定代码部分”的时间。
              • 我发现它在创建自定义控件时很有用。然后你经常在一个类中覆盖很多方法和属性,所以我们将它分成逻辑组(例如“control.Input.cs”、“control.Draw.cs”、“control.Properties”等) .
              猜你喜欢
              • 1970-01-01
              • 2010-11-16
              • 1970-01-01
              • 1970-01-01
              • 2010-11-29
              • 2010-12-31
              • 2018-05-20
              • 2020-01-01
              • 1970-01-01
              相关资源
              最近更新 更多