Answers:
局部类的最大用途是使代码生成器/设计人员的工作更加轻松。部分类使生成器可以简单地发出需要发出的代码,而不必处理用户对文件的编辑。用户同样可以通过拥有第二部分类来自由地用新成员为类添加注释。这为分离关注点提供了一个非常干净的框架。
观察它的更好方法是在局部类之前了解设计器的功能。WinForms设计器会在区域内吐出所有代码,并带有措辞强烈的注释,说明不要修改代码。它必须插入各种试探法以找到生成的代码,以供以后处理。现在,它可以简单地打开designer.cs文件,并高度确信它仅包含与设计者相关的代码。
另一个用途是拆分不同接口的实现,例如:
partial class MyClass : IF1, IF2, IF3
{
// main implementation of MyClass
}
partial class MyClass
{
// implementation of IF1
}
partial class MyClass
{
// implementation of IF2
}
Implements
关键字表示该方法属于接口)
除了其他答案...
我发现它们作为重构神级的垫脚石很有用。如果一个类有多个职责(特别是如果它是一个很大的代码文件),那么我发现将每个职责的1x部分类添加为组织和重构代码的第一步是有益的。
这有很大帮助,因为它可以帮助使代码更具可读性,而不会实际影响执行行为。它还可以帮助确定何时易于分解责任或与其他方面紧密联系在一起。
但是-要清楚-这仍然是不好的代码,在开发结束时,您仍然希望每个类一个责任(而不是每个部分类)。这只是一块垫脚石:)
仅部分方法声明即使代码仅使用方法声明进行编译,并且如果不存在该方法的实现,编译器也可以安全地删除该代码段,并且不会发生编译时错误。
验证点4。只需创建一个winform项目,并在Form1构造函数之后添加此行,然后尝试编译代码
partial void Ontest(string s);
以下是实现部分类时要考虑的几点:-
一个很好的用途是将生成的代码与属于同一类的手写代码分开。
例如,由于LINQ to SQL使用局部类,因此您可以编写某些功能(例如多对多关系)的自己的实现,并且重新生成代码时,这些自定义代码不会被覆盖。
WinForms代码也是如此。Designer生成的所有代码都放在一个您通常不会触摸的文件中。您的手写代码位于另一个文件中。这样,当您在Designer中进行更改时,所做的更改不会被删除。
确实,Partial 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.
另一个可能的用途是,不止一个开发人员可以在同一个类上工作,因为他们存储在不同的位置。人们可能会笑,但您永远不知道有时候它可能很少。
public partial class Product
{
//you are writing the business logic for fast moving product
}
public partial class Product
{
// Another developer writing some business logic...
}
希望有道理!
局部类跨越多个文件。
如何在C#类声明上使用partial修饰符?
使用部分类,您可以将一个类物理上分成多个文件。这通常是由代码生成器完成的。
例
对于普通的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
修饰符,将收到包含以下文本的错误:
[名称空间'
<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");
}
}
摘要
在使用大型班级或团队工作时,尽可能使所有内容保持整洁,您可以编辑而不覆盖(或始终提交更改)
如果您有足够大的类无法进行有效的重构,则将其分为多个文件有助于使事情井井有条。
例如,如果您有一个包含讨论论坛和产品系统的网站的数据库,并且不想创建两个不同的提供程序类(请注意,与代理类不是同一件事),则可以在不同的文件中创建一个局部类,例如
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..
}
多数人指出,此方法partial
仅应用于具有生成的代码文件的类或接口。我不同意,这就是原因。
例如,让我们看一下C#System.Math类...那是class。我不会尝试将70多种方法全部塞入同一代码文件中。维持这将是一场噩梦。
将每种数学方法放入项目的单独的部分类文件中,并将所有代码文件放入项目中的Math文件夹中,将会大大简化组织。
对于具有大量不同功能的许多其他类,同样/可能适用。例如,用于管理PrivateProfile API的类可能会因为在单个项目文件夹中被分成一组干净的部分类文件而受益。
就个人而言,我还将大多数人称为“ helper”或“ utility”的类划分为每个方法或方法功能组的单独的部分文件。例如,在一个项目中,字符串帮助器类具有近50种方法。即使使用区域,那也将是一个很长的笨拙的代码文件。对于每种方法,使用单独的部分类文件进行维护非常容易。
在执行此操作时,我会小心使用局部类,并在整个项目中保持所有代码文件的布局一致。例如,将任何类公共枚举和类私有成员放入Common.cs或文件夹中类似名称的文件中,而不是将它们散布到整个文件中,除非它们仅特定于它们所包含的部分文件。
请记住,将类拆分为单独的文件时,您还将失去使用文本编辑器拆分器栏的能力,该栏使您可以同时查看当前文件的两个不同部分。
局部类使得仅通过添加源文件就可以向适当设计的程序中添加功能。例如,可以设计一个文件导入程序,以便可以通过添加处理文件的模块来添加不同类型的已知文件。例如,主文件类型转换器可以包括一个小类:
局部公共类zzFileConverterRegistrar 事件寄存器(ByVal mainConverter作为zzFileConverter) 子registerAll(ByVal mainConverter为zzFileConverter) RaiseEvent寄存器(mainConverter) 结束子 最终班
每个希望注册一种或多种类型的文件转换器的模块都可以包含以下内容:
局部公共类zzFileConverterRegistrar 私有子寄存器Gif(ByVal mainConverter as zzFileConverter)处理我。 mainConverter.RegisterConverter(“ GIF”,GifConverter.NewFactory)) 结束子 最终班
请注意,主文件转换器类不是“公开的”,它只是公开了一个附加模块可以连接的小桩类。命名冲突有轻微的风险,但是如果每个加载项模块的“注册”例程均根据其处理的文件类型进行命名,则它们可能不会造成问题。如果有人担心这样的事情,可以将GUID粘贴在注册子例程的名称中。
编辑/附录 明确地说,这样做的目的是提供一种方法,使各种不同的类可以让主程序或类知道它们。主文件转换器使用zzFileConverterRegistrar要做的唯一一件事就是创建它的一个实例,并调用registerAll方法,该方法将触发Register事件。任何想要挂接到该事件的模块都可以执行任意代码以响应该事件(这就是整个思路),但是除了定义名称与其他名称匹配的方法外,不正确地扩展zzFileConverterRegistrar类也无法实现任何模块功能。一个不正确编写的扩展名肯定可以破坏另一个不正确编写的扩展名,但是对于那些不希望其扩展名被破坏的人来说,解决方案就是简单地正确编写它。
在不使用部分类的情况下,可以在主文件转换器类中的某处有一些代码,如下所示:
RegisterConverter(“ GIF”,GifConvertor.NewFactory) RegisterConverter(“ BMP”,BmpConvertor.NewFactory) RegisterConverter(“ JPEG”,JpegConvertor.NewFactory)
但是添加另一个转换器模块将需要进入转换器代码的这一部分,并将新的转换器添加到列表中。不再需要使用部分方法-所有转换器将自动包含在内。
IModule
接口呢?
IModule
,你可以使用插件框架状MEF(只是其中之一),等等等等
从MSDN:
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 { }
}
这里列出了部分类的一些优点。
您可以将UI设计代码和业务逻辑代码分开,以使其易于阅读和理解。例如,您正在使用Visual Studio开发Web应用程序,并添加一个新的Web表单,那么就有两个源文件“ aspx.cs”和“ aspx.designer.cs”。这两个文件具有相同的类,但带有partial关键字。“ .aspx.cs”类具有业务逻辑代码,而“ aspx.designer.cs”具有用户界面控件定义。
使用自动生成的源代码时,可以将代码添加到类中,而无需重新创建源文件。例如,您正在使用LINQ to SQL并创建一个DBML文件。现在,当您拖放表格时,它将在designer.cs中创建一个局部类,并且所有表格列均在该类中具有属性。您需要在此表中添加更多列以绑定到UI网格上,但是您不想在数据库表中添加新列,因此可以为此类创建一个单独的源文件,该文件对该列具有新属性,并且它将成为部分课程。因此,这确实会影响数据库表与DBML实体之间的映射,但是您可以轻松地获得一个额外的字段。这意味着您可以自己编写代码,而不会弄乱系统生成的代码。
多个开发人员可以同时编写该类的代码。
您可以通过压缩大型类来更好地维护您的应用程序。假设您有一个具有多个接口的类,因此您可以根据接口实现来创建多个源文件。易于理解和维护实现的接口,源文件在该接口上具有部分类。
每当我有一个包含大小或复杂性高partial
的嵌套类的类时,我都会将该类标记为并将该嵌套类放在单独的文件中。我使用以下规则命名包含嵌套类的文件:[类名]。[嵌套类名] .cs。
以下MSDN博客介绍了如何使用带有嵌套类的部分类来实现可维护性:http : //blogs.msdn.com/b/marcelolr/archive/2009/04/13/using-partial-classes-with-nested-classes-for-可维护性
我知道这个问题确实很老,但我只想补充一下部分课程。
我个人使用部分类的原因之一是在为程序(尤其是状态机)创建绑定时。
例如,OpenGL是一个状态机,有堆是都可以但是在全球范围改变,以我的经验结合类似于OpenGL的情况下有这么多的方法什么方法,类可以很容易地超过10K LOC。
局部类将为我分解这种情况,并帮助我快速找到方法。
引入部分类主要是为了帮助代码生成器,因此,我们(用户)最终不会在每次重新生成时失去对ASP.NET的.designer.cs类(例如ASP.NET的.designer.cs类)的所有工作/更改。代码LINQ,EntityFrameworks,ASP.NET使用部分类生成代码,因此我们可以利用部分类和方法安全地添加或更改这些生成代码的逻辑,但是在使用部分类向生成的代码添加内容之前,请务必格外小心如果我们中断构建会更容易,但是如果引入运行时错误则会更糟。有关更多详细信息,请参见http://www.4guysfromrolla.com/articles/071509-1.aspx
我注意到在用法中找不到的两种用法。
一些开发人员使用注释来分隔类的不同“部分”。例如,一个团队可能使用以下约定:
public class MyClass{
//Member variables
//Constructors
//Properties
//Methods
}
对于部分类,我们可以更进一步,并将这些部分拆分为单独的文件。按照惯例,团队可以在每个文件后缀对应的部分。因此,在上面,我们将具有以下内容:MyClassMembers.cs,MyClassConstructors.cs,MyClassProperties.cs,MyClassMethods.cs。
正如其他答案所暗示的,在这种情况下,是否值得拆分班级可能取决于班级的规模。如果很小,将所有内容都放在一个大师班中可能会更容易。但是,如果这些部分中的任何一个太大,则可以将其内容移到单独的局部类中,以使主类保持整洁。在这种情况下,一个约定可能是在标题部分之后留下诸如“请参阅部分类”之类的注释,例如:
//Methods - See partial class
这可能很少发生,但是您要使用的库中的两个函数之间可能存在名称空间冲突。在单个类中,最多可以为其中一个使用using子句。对于另一个,您需要一个完全限定的名称或别名。对于部分类,由于每个名称空间和using语句列表都不相同,因此可以将两组函数分成两个单独的文件。
using Library1 = The.Namespace.You.Need
或global::Root.Of.Namespace