什么时候适合使用C#部分类?

我是新来的部分类,并想知道是否有人可以给我一个概述,为什么我会使用它们,我会在这个过程中获得什么优势。

部分类的最大用处是使代码生成器/devise器的生活更轻松。 部分类允许生成器简单地省略他们需要省略的代码,而不必处理用户对文件的编辑。 用户同样可以自由地用新的成员通过具有第二部分类来注释该类。 这为分离问题提供了一个非常干净的框架。

看看它的一个更好的方法是看看devise者在部分类之前是如何运作的。 WinFormsdevise师将吐出一个区域内的所有代码,并强调措辞不要修改代码。 它不得不插入各种启发式来查找生成的代码以供以后处理。 现在可以简单地打开designer.cs文件,并且高度自信地仅包含与devise者相关的代码。

另一个用途是拆分不同接口的实现,例如:

partial class MyClass : IF1, IF2, IF3 { // main implementation of MyClass } partial class MyClass { // implementation of IF1 } partial class MyClass { // implementation of IF2 } 

除了其他的答案…

我发现它们在重构神级中作为一个垫脚石是有帮助的。 如果一个类有多重责任(尤其是如果它是一个非常大的代码文件),那么我认为将1个部分类每个责任添加为组织的第一遍,然后重构代码是有益的。

这非常有帮助,因为它可以帮助使代码更加可读,而不会影响执行行为。 它还可以帮助识别责任何时易于重构或与其他方面紧密相关。

然而 – 要清楚 – 这仍然是不好的代码,在开发结束时,你仍然想要每个类的责任( 不是每个部分类)。 这只是一个垫脚石:)

  1. 使用部分类的多个开发人员多个开发人员可以轻松地在同一个类上工作。
  2. 代码生成器代码生成器主要使用部分类来区分不同的问题
  3. 部分方法使用部分类也可以定义部分方法,开发人员可以简单地定义方法,而其他开发人员可以实现该方法。
  4. 只有部分方法声明即使代码用方法声明进行编译,如果方法的实现不存在,编译器可以安全地删除这段代码,并且不会发生编译时错误。

    validation第4点。只要创build一个winform项目并在Form1构造函数之后包含这一行,并尝试编译代码

     partial void Ontest(string s); 

以下是在实现部分类时需要考虑的几点:

  1. 在部分类的每个部分使用partial关键字。
  2. 部分类的每个部分的名称应该相同,但部分类的每个部分的源文件名可以不同。
  3. 部分类的所有部分应该位于相同的命名空间中。
  4. 部分类的每个部分应该位于同一个程序集或DLL中,换句话说,您不能在不同的类库项目的源文件中创build部分类。
  5. 部分类的每个部分必须具有相同的可访问性。 (即:私人,公共或受保护)
  6. 如果您inheritance了部分类的类或接口,则该部分类的所有部分都会inheritance它。
  7. 如果部分class级的一部分被封闭,那么整个class级将被封闭。
  8. 如果部分类的一部分是抽象的,那么整个类将被视为一个抽象类。

一个很好的用途是将生成的代码与属于同一类的手写代码分开。

例如,因为LINQ to SQL使用部分类,所以您可以编写自己的某些function块的实现(如多对多关系),并且在重新生成代码时,这些自定义代码段不会被覆盖。

WinForms代码也一样。 所有Designer生成的代码都放在一个通常不会触及的文件中。 你的手写代码放在另一个文件中。 这样,当您在Designer中更改某些内容时,您的更改不会被吹掉。

部分类是用于自动代码生成的,一个用途可以是维护一个可能有一千行代码的大类文件。 你永远不会知道你的class级可能会有一万行,而你不想创build一个不同名字的新class级。

 public partial class Product { // 50 business logic embedded in methods and properties.. } public partial class Product { // another 50 business logic embedded in methods and properties.. } //finally compile with product.class file. 

另一个可能的用途可能是多个开发人员可以在同一个class上工作,因为他们存储在不同的地方。 人们可能会笑,但你永远不知道这可能是less数有时。

Product1.cs

 public partial class Product { //you are writing the business logic for fast moving product } 

Product2.cs

 public partial class Product { // Another developer writing some business logic... } 

希望这是有道理的!

在处理大型课程时尽可能保持干净,或者在团队中工作时,可以不必重写(或始终提交更改)

部分类的主要用途是生成的代码。 如果您查看WPF(Windows Presentation Foundation)networking,则使用标记(XML)定义您的UI。 该标记被编译成部分类。 你用你自己的部分类来填充代码。

部分类跨越多个文件。

How can you use the partial modifier on a C# class declaration?

有了部分,你可以物理上将一个类分成多个文件。

这通常由代码生成器完成。

使用普通的C#类,您不能在同一个项目中的两个单独的文件中声明一个类。

但是用部分修饰符,你可以。

如果一个文件通常被编辑,而另一个文件是机器生成的或很less被编辑的,这是非常有用的。

An Example will clear your concept.

 class Program { static void Main() { A.A1(); A.A2(); } } //Contents of file A1.cs: C# using System; partial class A { public static void A1() { Console.WriteLine("A1"); } } //Contents of file A2.cs: C# using System; partial class A { public static void A2() { Console.WriteLine("A2"); } } Output A1 A2 

部分在这里是必需的。

If you remove the partial modifier, you will get an error containing this text: [The namespace '<global namespace>' already contains a definition for 'A'].

提示:要解决这个问题,您可以使用partial关键字,也可以更改其中一个类名称。

How does the C# compiler deal with partial classes?

如果你反汇编上面的程序,你会看到文件A1.cs和A2.cs被删除。

你会发现类A是存在的。

IL Disassembler So:A类将在同一代码块中包含方法A1和A2。 两个class合并为一个class。

编译A1.cs和A2.cs的结果:C#

 internal class A { // Methods public static void A1() { Console.WriteLine("A1"); } public static void A2() { Console.WriteLine("A2"); } } 

概要

部分类可以简化某些C#编程的情况。

在创buildWindows窗体/ WPF程序时,经常在Visual Studio中使用它们。

机器生成的C#代码是分开的。

或者你可以在这里find整个描述。

如果你有足够大的类不适合有效的重构,把它分成多个文件有助于保持组织。

例如,如果你有一个包含讨论论坛和产品系统的站点的数据库,并且你不想创build两个不同的提供者类(与代理类不同,只是要清楚),你可以在不同的文件中创build一个单独的部分类

MyProvider.cs – 核心逻辑

MyProvider.Forum.cs – 专门针对论坛的方法

MyProvider.Product.cs – 产品的方法

这是保持组织安全的另一种方式。

而且,正如其他人所说的那样,这是将方法添加到生成的类的唯一方法,而不会在下次重新生成类时冒着添加被破坏的风险。 这在模板生成(T4)代码,ORM等方面很有用。

我看到的另一个用途是,

扩展了一个关于数据访问逻辑的大抽象类,

我有名称Post.cs,Comment.cs,Pages.cs的各种文件…

 in Post.cs public partial class XMLDAO :BigAbstractClass { // CRUD methods of post.. } in Comment.cs public partial class XMLDAO :BigAbstractClass { // CRUD methods of comment.. } in Pages.cs public partial class XMLDAO :BigAbstractClass { // CRUD methods of Pages.. } 

服务引用是另一个例子,其中部分类用于将生成的代码与用户创build的代码分开。

您可以“扩展”服务类,而不必在更新服务引用时覆盖它们。

作为预编译器指令的替代方法。

如果你使用预编译器指令(即#IF DEBUG ),那么你最终会看到一些与你的实际版本代码混杂在一起的粗糙的代码。

你可以创build一个单独的partial-class来包含这个代码,并且把整个partial类包装在一个指令中,或者把这个代码文件从发送到编译器(实际上是这样做的)中省略掉。

部分类可以仅通过添加源文件就可以将function添加到适当devise的程序中。 例如,可以devise文件导入程序,以便通过添加处理它们的模块来添加不同types的已知文件。 例如,主文件types转换器可以包含一个小类:

 部分公共类zzFileConverterRegistrar
    事件寄存器(ByVal mainConverter as zzFileConverter)
     Sub registerAll(ByVal mainConverter as zzFileConverter)
         RaiseEvent寄存器(mainConverter)
    结束小组
末class 

希望注册一个或多个types的文件转换器的每个模块都可以包含如下内容:

部分公共类zzFileConverterRegistrar
     Private Sub RegisterGif(ByVal mainConverter as zzFileConverter)处理Me.Register
         mainConverter.RegisterConverter(“GIF”,GifConverter.NewFactory))
    结束小组
末class

请注意,主文件转换器类不是“暴露”的 – 它只是公开一些附加模块可以挂钩的stub类。 命名冲突的风险很小,但是如果每个插件模块的“注册”例程是根据它处理的文件的types命名的,那么它们可能不会造成问题。 如果有人担心这种情况,可以用注册子程序的名字来粘一个GUID。

编辑/附录为了清楚起见,这样做的目的是提供一种手段,通过这种手段,各种单独的课程可以让主程序或课程知道它们。 主要的文件转换器将与zzFileConverterRegistrar做的唯一的事情是创build它的一个实例,并调用registerAll方法,将触发注册事件。 任何想要钩住这个事件的模块都可以执行任意代码来响应它(这就是整个想法),但是除了定义一个名称与其他名称相匹配的方法之外,没有任何模块可以通过不正确地扩展zzFileConverterRegistrar类。 一个不正确的书面扩展肯定会有可能打破另一个不正确的书面扩展,但是解决scheme是不希望他的扩展被破坏的人简单地写出来。

可以不使用部分类,而是在主文件转换器类的某个地方有一些代码,如下所示:

   RegisterConverter(“GIF”,GifConvertor.NewFactory)
   RegisterConverter(“BMP”,BmpConvertor.NewFactory)
   RegisterConverter(“JPEG”,JpegConvertor.NewFactory)

但添加另一个转换器模块需要进入转换器代码的这一部分,并将新的转换器添加到列表中。 使用部分方法,这不再是必要的 – 所有的转换器将被自动包含。

大多数人都认为partial应该只用于具有生成代码文件或接口的类。 我不同意,这是为什么。

举一个例子,让我们看看C#System.Math类…这是 。 我不会试图将70多种方法全部放入同一个单独的代码文件中。 这将是一个噩梦维持。

将每个math方法放入单独的部分类文件中,并将所有代码文件放置到项目中的Math文件夹中,这样的组织就会更加清晰。

对于具有大量不同function的许多其他类也是如此。 例如,用于pipe理PrivateProfile API的类可以通过在单个项目文件夹中拆分为干净的部分类文件来获益。

就我个人而言,我也将大多数人称之为“助手”或“实用工具”的类别分成每个方法或方法function组的单个部分文件。 例如在一个项目中,string帮助类有近50个方法。 即使使用区域,这将是一个冗长的笨重的代码文件。 对于每种方法,使用单独的部分类文件要明显容易得多。

我只是小心使用部分类,并保持整个项目中的所有代码文件布局一致。 例如,将任何类公共枚举和类私有成员放置到文件夹中的Common.cs或类似名称的文件中,而不是跨文件扩展它们,除非它们仅针对它们所包含的部分文件。

请记住,当你将一个类拆分成不同的文件时,你也将失去使用文本编辑器拆分栏的能力,这个拆分栏允许你同时查看当前文件的两个不同部分。

部分类最近帮助了源代码控制,其中多个开发人员将一个文件添加到文件的相同部分(由Resharper自动化)中添加新的方法。

这些推到混帐引起合并冲突。 我发现没有办法告诉合并工具采取新的方法作为一个完整的代码块。

在这方面的部分类允许开发者坚持他们的文件的版本,我们可以在以后手工合并它们。

例如 –

  • MainClass.cs – 保存字段,构造函数等
  • MainClass1.cs – 开发人员实施的新代码
  • MainClass2.cs – 是新代码的另一个开发人员类。

来自MSDN :

在编译时,部分types定义的属性被合并。 例如,请考虑以下声明:

 [SerializableAttribute] partial class Moon { } [ObsoleteAttribute] partial class Moon { } 

它们相当于以下声明:

 [SerializableAttribute] [ObsoleteAttribute] class Moon { } 

以下是从所有部分types定义中合并的:

  • XML评论

  • 接口

  • 通用types的参数属性

  • 类属性

  • 会员

2.另一件事,嵌套的部分类也可以是部分的:

 partial class ClassWithNestedClass { partial class NestedClass { } } partial class ClassWithNestedClass { partial class NestedClass { } } 

这里列出了部分类的一些优点。

您可以将UIdevise代码和业务逻辑代码分开,以便阅读和理解。 例如,您正在使用Visual Studio开发一个Web应用程序,并添加一个新的Web表单,然后有两个源文件“aspx.cs”和“aspx.designer.cs”。 这两个文件与partial关键字具有相同的类。 “.aspx.cs”类具有业务逻辑代码,而“aspx.designer.cs”具有用户界面控制定义。

使用自动生成的源代码时,可以将代码添加到类中,而无需重新创build源文件。 例如,您正在使用LINQ to SQL并创build一个DBML文件。 现在,当你拖放一个表时,它会在designer.cs中创build一个部分类,并且所有的表列在类中都有属性。 您需要在此表中绑定更多的列,但不希望将新列添加到数据库表中,因此您可以为该类创build一个单独的源文件,该文件具有该列的新属性,它将成为一个分class。 所以这确实会影响数据库表和DBML实体之间的映射,但是您可以轻松地获得额外的字段。 这意味着您可以自己编写代码,而不会混淆系统生成的代码。

不止一个开发者可以同时编写这个类的代码。

您可以通过压缩大型类来更好地维护您的应用程序。 假设你有一个有多个接口的类,所以你可以根据接口实现创build多个源文件。 很容易理解和维护一个实现的源文件具有部分类的接口。

每当我有一个包含任何重要大小/复杂度的嵌套类的类时,我将该类标记为partial ,并将嵌套类放在一个单独的文件中。 我使用规则命名包含嵌套类的文件:[class name]。[nested class name] .cs。

下面的MSDN博客解释了使用具有嵌套类的部分类进行可维护性: http : //blogs.msdn.com/b/marcelolr/archive/2009/04/13/using-partial-classes-with-nested-classes-for- maintainability.aspx

部分类主要是为了帮助代码生成器而引入的,所以我们(用户)最终不会丢失我们所有的工作/更改,比如每次重新生成ASP.NET的.designer.cs类时生成的类,几乎所有的新工具代码LINQ,EntityFrameworks,ASP.NET使用生成的代码的部分类,所以我们可以安全地添加或更改这些生成的代码的逻辑利用部分类和方法,但要非常小心,然后添加东西到生成的代码使用部分类如果我们打破构build它更容易,但如果我们引入运行时错误最糟糕。 欲了解更多详情,请查阅http://www.4guysfromrolla.com/articles/071509-1.aspx