什么时候使用c#部分类比较合适?

我想知道是否有人能给我一个概述,为什么我要使用它们,在这个过程中我能获得什么好处。

218467 次浏览

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

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

WinForms代码也是如此。所有设计器生成的代码都放在一个文件中,您通常不会接触这个文件。手写的代码放到另一个文件中。这样,当您在设计器中更改某些内容时,您所做的更改不会被影响。

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

部分类的最大用途是使代码生成器/设计人员的工作更轻松。部分类允许生成器简单地发出它们需要发出的代码,而不需要处理用户对文件的编辑。用户同样可以通过创建第二个分部类来自由地用新成员注释类。这为关注点分离提供了一个非常清晰的框架。

更好的方法是看看设计器在部分类之前是如何工作的。WinForms设计器会吐出区域内的所有代码,并给出不修改代码的强烈注释。它必须插入各种启发式方法来找到生成的代码,以便稍后进行处理。现在它可以简单地打开designer.cs文件,并有高度的信心它只包含与设计器相关的代码。

如果您有一个足够大的类,而不适合进行有效的重构,那么将它分离到多个文件中有助于保持内容的组织性。

例如,如果您有一个包含论坛和产品系统的站点数据库,并且您不想创建两个不同的提供者类(与代理类不是一回事,只是为了清楚起见),您可以在不同的文件中创建单个分部类,例如

——核心逻辑

cs -专门与论坛相关的方法

产品的方法

这是另一种让事情井井有条的方法。

另外,正如其他人所说,这是向生成的类添加方法而不会在下次重新生成类时破坏所添加的方法的唯一方法。这对于模板生成的(T4)代码、orm等非常方便。

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

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

除了其他答案之外……

我发现它们可以作为重构神类的垫脚石。如果一个类有多个职责(特别是如果它是一个非常大的代码文件),那么我发现为每个职责添加1x个部分类作为组织和重构代码的第一步是有益的。

这非常有帮助,因为它可以帮助使代码更具可读性,而不会实际影响执行行为。它还可以帮助确定何时易于重构某个职责,或者何时与其他方面紧密纠缠在一起。

然而,需要明确的是,这仍然是糟糕的代码,在开发结束时,您仍然希望每个类有一个职责(每个分部类不< em > < / em >)。这只是一块垫脚石:)

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

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

你可以创建一个单独的分部类来包含这些代码,或者将整个分部类包装在一个指令中,或者省略该代码文件,使其不被发送给编译器(实际上是做同样的事情)。

在处理大型类时,或在团队中工作时,尽可能保持所有内容的干净,您可以在不重写的情况下编辑(或始终提交更改)

通过部分类,只需添加源文件,就可以向适当设计的程序添加功能。例如,可以设计一个文件导入程序,这样就可以通过添加处理文件的模块来添加不同类型的已知文件。例如,主文件类型转换器可以包含一个小类:

Partial Public Class zzFileConverterRegistrar
Event Register(ByVal mainConverter as zzFileConverter)
Sub registerAll(ByVal mainConverter as zzFileConverter)
RaiseEvent Register(mainConverter)
End Sub
End Class

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

Partial Public Class zzFileConverterRegistrar
Private Sub RegisterGif(ByVal mainConverter as zzFileConverter) Handles Me.Register
mainConverter.RegisterConverter("GIF", GifConverter.NewFactory))
End Sub
End Class

注意,主文件转换器类并没有“公开”——它只是公开了一个小存根类,外接程序模块可以钩子到这个存根类。存在命名冲突的轻微风险,但如果每个外接程序模块的“寄存器”例程是根据它处理的文件类型命名的,那么它们可能不会造成问题。如果担心这样的事情,可以在注册子例程的名称中插入GUID。

< b >编辑/补遗 需要明确的是,这样做的目的是提供一种方法,通过这种方法,各种单独的类可以让主程序或类知道它们。主文件转换器使用zzFileConverterRegistrar要做的唯一一件事是创建它的一个实例并调用registerAll方法,该方法将触发Register事件。任何想要钩住该事件的模块都可以执行任意代码来响应它(这就是整个思想),但是模块不能通过不恰当地扩展zzFileConverterRegistrar类来做任何事情,只能定义一个名称与其他方法名称匹配的方法。一个写得不正确的扩展破坏另一个写得不正确的扩展当然是可能的,但解决这个问题的解决方案是,对于任何不想让他的扩展破坏的人来说,只要正确地编写它

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

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

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

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

partial class MyClass : IF3
{
// main implementation of MyClass
}




partial class MyClass : IF1
{
// implementation of IF1
}


partial class MyClass : IF2
{
// implementation of IF2
}

引入部分类主要是为了帮助代码生成器,这样我们(用户)就不会把所有的工作/更改都浪费在生成的类上,比如ASP。每次我们重新生成。NET的。designer.cs类时,几乎所有生成代码的新工具LINQ, EntityFrameworks, ASP。NET对生成的代码使用partial类,所以我们可以利用partial类和方法安全地添加或改变这些生成代码的逻辑,但是在使用partial类向生成的代码中添加东西之前要非常小心,如果我们破坏了构建,它会更容易,但如果我们引入运行时错误,则会更糟糕。要了解更多细节,请查看https://web.archive.org/web/20211020111732/https://www.4guysfromrolla.com/articles/071509-1.aspx

我看到的另一个用法是,

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

我有各种文件的名字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..
}

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

这些推入git会导致合并冲突。我发现没有办法告诉合并工具把新方法作为一个完整的代码块。

在这方面,部分类允许开发人员坚持他们文件的一个版本,并且我们可以稍后手工将它们合并回去。

的例子,

  • cs—保存字段、构造函数等
  • MainClass1.cs—开发人员实现时的新代码
  • cs -是另一个用于新代码的开发人员类。

的确,Partial Class用于自动代码生成,其中一个用途是维护一个可能有上千行代码的大型类文件。你永远不知道你的类最终会有1万行,你不想用不同的名字创建一个新类。

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.

另一个可能的用途是多个开发人员可以使用同一个类,因为它们存储在不同的地方。人们可能会笑,但你永远不知道有时候情况会很棘手。

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...
}

希望这是有意义的!

大多数人指出,partial应该只用于具有生成代码文件的类或接口。我不同意,原因如下。

举个例子,让我们看看c#系统。数学课…这是# EYZ0。我不会尝试把70多个方法都塞进同一个代码文件中。维持它将是一场噩梦。

将每个数学方法放入单独的部分类文件中,并将所有代码文件放入项目中的math文件夹中,将显著地使组织更加干净。

同样的道理也适用于许多其他具有大量不同功能的类。例如,管理PrivateProfile API的类可以通过在单个项目文件夹中拆分为一组干净的部分类文件而受益。

就我个人而言,我还将大多数人所说的“助手”或“实用工具”类划分为每个方法或方法功能组的单独部分文件。例如,在一个项目中,字符串助手类几乎有50个方法。即使使用区域,这也将是一个冗长而笨拙的代码文件。为每个方法使用单独的部分类文件维护要容易得多。

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

请记住,当您将一个类拆分为单独的文件时,您也失去了使用文本编辑器拆分栏的能力,该功能可以让您同时查看当前文件的两个不同部分。

    使用分部类多个开发人员可以在同一个类上工作 很容易。李< / > 分部类主要被代码生成器用来保存 不同的关注点分开
  1. 使用分部类,你也可以定义分部方法,其中一个开发人员可以简单地定义方法,另一个开发人员可以实现它。
  2. 即使是代码也只能通过方法声明和if实现来编译 的方法不存在编译器可以安全地删除那块

    .代码,没有编译时错误

    来验证第四点。只需创建一个winform项目,并在Form1构造函数之后包含这一行,并尝试编译代码

    partial void Ontest(string s);
    

Here are some points to consider while implementing partial classes:-

  1. Use partial keyword in each part of partial class.
  2. The name of each part of partial class should be the same but the source file name for each part of partial class can be different.
  3. All parts of a partial class should be in the same namespace.
  4. Each part of a partial class should be in the same assembly or DLL, in other words you can't create a partial class in source files from a different class library project.
  5. Each part of a partial class must have the same accessibility. (i.e: private, public or protected)
  6. If you inherit a class or interface on a partial class then it is inherited by all parts of that partial class.
  7. If a part of a partial class is sealed then the entire class will be sealed.
  8. If a part of partial class is abstract then the entire class will be considered an abstract class.

分部类跨越多个文件。

如何在c#类声明中使用分部修饰符?

使用部分类,您可以将一个类物理地分离到多个文件中。这通常由代码生成器完成。

例子

对于普通的c#类,您不能在同一个项目中的两个独立文件中声明一个类。但是使用partial修饰符,你可以。

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

这里有一个例子来说明:

class Program
{
static void Main()
{
A.A1();
A.A2();
}
}

A1.cs文件内容:c#

using System;


partial class A
{
public static void A1()
{
Console.WriteLine("A1");
}
}

A2.cs文件内容:c#

using System;


partial class A
{
public static void A2()
{
Console.WriteLine("A2");
}
}

输出:

A1
A2

这里需要Partial。

如果你移除partial修饰符,你将得到一个包含以下文本的错误:

[名称空间'<global namespace>'已经包含了'A'的定义]。

提示:

要解决这个问题,您可以使用partial关键字,或者更改其中一个类名。

c#编译器如何处理部分类?

如果你分解上面的程序(使用IL Disassembler),你会看到文件A1.cs和A2.cs被删除了。你会发现A类出现了。

类A将在同一个代码块中包含方法A1和A2。这两个班合并为一个班。

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

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


public static void A2()
{
Console.WriteLine("A2");
}
}

总结

  • 部分类可以简化某些c#编程情况。
  • 当创建Windows窗体/WPF程序时,通常在Visual Studio中使用它们。
  • 机器生成的c#代码是独立的。
  • 或者你可以找到整个描述在这里

下面列出了部分类的一些优点。

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

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

多个开发人员可以同时为类编写代码。

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

从# EYZ0:

1.在编译时,合并部分类型定义的属性。例如,考虑以下声明:

[SerializableAttribute]
partial class Moon { }


[ObsoleteAttribute]
partial class Moon { }

它们等价于以下声明:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

以下是所有部分类型定义的合并:

  • XML注释

  • 接口

  • 泛型类型参数属性

  • 类属性

  • 成员

2.另外,嵌套的分部类也可以是分部类:

partial class ClassWithNestedClass
{
partial class NestedClass { }
}


partial class ClassWithNestedClass
{
partial class NestedClass { }
}

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

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

我知道这个问题很老了,但我想补充一下我对部分课程的看法。

我个人使用部分类的一个原因是当我为程序创建绑定时,尤其是状态机。

例如,OpenGL是一个状态机,有的方法都可以全局更改,然而,根据我的经验,绑定类似于OpenGL的东西,其中有很多方法,类很容易超过10k LOC。

部分类将为我打破这个而且帮助我快速找到方法。

我注意到两个用法,我在答案中没有明确找到。

分类项目分组

一些开发人员使用注释来分离类的不同“部分”。例如,一个团队可能使用以下约定:

public class MyClass{
//Member variables
//Constructors
//Properties
//Methods
}

对于分部类,我们可以更进一步,将部分分割到单独的文件中。按照惯例,团队可以在每个文件后面加上与之对应的部分。所以在上面我们会有这样的东西:MyClassMembers.cs, MyClassConstructors.cs, MyClassProperties.cs, MyClassMethods.cs。

正如其他答案所暗示的那样,是否值得将班级分开可能取决于在这种情况下班级的规模。如果它很小,那么把所有东西都放在一个大师班可能会更容易。但是,如果这些部分中的任何一部分太大,它的内容可以移动到一个单独的分部类中,以保持主类的整洁。在这种情况下,惯例可能是在节标题后留下类似“See partial class”的注释,例如:

//Methods - See partial class

管理使用语句/命名空间的范围

这种情况可能很少发生,但是来自您想要使用的库的两个函数之间可能会发生名称空间冲突。在单个类中,最多只能为其中一个使用using子句。对于另一种,您需要一个完全限定的名称或别名。对于分部类,因为每个命名空间&使用语句列表则不同,可以将这两组函数分离到两个单独的文件中。

我发现令人不安的是,“凝聚力”这个词在这些帖子中没有出现(直到现在)。 我也很不安,有人认为启用或鼓励大型类和方法在某种程度上是件好事。 如果你试图理解和维护代码基的“部分”,那就糟透了