等待着元宵节的到来,过完元宵,这个年也算是过完了,也得开始出去挣钱了,过年回家感觉每个人都觉得很牛,只有自己太渣,为了避免年底再出现这样尴尬的局面,还是需要努力干活。争取当上CEO,赢取白富美,走上人生巅峰。(生活需要幻想,也需要面对现实,努力获取一个向上的心态,比起拥有财富要更加的难得。)
对于现在还在聊QQ和看文章的同志们,我只想借用上图问一句“你们不上班么?...哈哈哈...”。好了,不扯淡了,开始我们今天的主题。
C#的类型中,我们知道最多的就是静态类,对于静态类的一些特性在这里就不做介绍了,因为对于一个.NET开发者来说,静态类的一些特性应该是有一定的掌握,并且在项目中应用的也是非常多。现在需要介绍的是另一种类型,那就是“分部类型”,对于“分部类型”的了解,很多人估计也就是知道而已,接下来就让我们一起来学习一个“分部类型”这一C#的语言特点。
学习“分部类型”,我们还是先来了解一下什么叫做“分部类型”。分部类型是指可以在多个源文件中为一个类型编写代码。对于分部类型的使用场景,使用最多的地方是部分代码是自动生成,而其他部分的代码为手写的类型。“分部类型”是由C#2.0时引入的。在继承链上存在一个不必要的链接,会引发某些问题或降低封装型。
我们现在对于分部类型的定义有一个大致的了解,以及对分部类型的应用场景也有一个初步的了解,接下来我们来看一下如何创建分部类型和分部类型的使用方法。
如果需要创建分部类型,我们只需要在涉及的每个文件的类型的声明部分添加一个上下文关键字partial。对于分部类型,编译器在编译之前就把所有的文件合并在一起了。在一个文件中代码可以调用另外一个文件中的代码。有如下代码:
SegmentType1.cs:
partial class SegmentType
{
private void Add()
{
Update();
}
private void Delete()
{
}
}
SegmentType2.cs
partial class SegmentType
{
private void Update()
{
Delete();
}
}
以上是对分部类型做了一个简单的申明和应用,这两个.CS文件在编译器编译之前就已经合并在一起了。对于分部类型不能在一个文件中编写成员的一半代码,而把另外一半代码放到另外一个文件中,必须保证每个独立的成员必须完整地位于它所处的文件中。如下代码:
SegmentType1.cs:
partial class SegmentType
{
private void Add(string fileName)
{
FileStream fs = null;
try
{
fs = File.Create(fileName);
}
}
}
SegmentType2.cs
partial class SegmentType
{
private void Update()
{
Add();
catch (ArgumentException arex)
{
throw arex;
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
}
}
上面演示的做法是无法通过编译的。
对于类型的声明还有一些限制,那就是声明必须要相互兼容,任何文件都能指定要实现的接口和基类型,以及类型参数的约束。如果多个文件都设定了基类型,那么它们必须是相同的,并且如果多个文件都设定了类型参数约束,那么约束必须是一致的。有如下代码实例:
SegmentType1.cs:
//接口约束:IEquatable<string>;
//where TFirst:class :和类型参数约束
partial class SegmentType<TFirst,TSecond>:IEquatable<string> where TFirst:class
{
//实现IEquatable<string>接口方法
public bool Equals(string other)
{
return false;
}
}
SegmentType2.cs
//指定基类:EventArgs
//指定接口:IDisposable
partial class SegmentType<TFirst, TSecond> :EventArgs,IDisposable
{
//实现方法
public void Dispose()
{
}
}
以上的接口和基类约束中,也可以使用如下方法:
SegmentType1.cs:
//接口约束:IEquatable<string>;
//where TFirst:class :和类型参数约束
partial class SegmentType<TFirst,TSecond>:IEquatable<string> where TFirst:class
{
//实现方法
public void Dispose()
{
}
}
SegmentType2.cs
//指定基类:EventArgs
//指定接口:IDisposable
partial class SegmentType<TFirst, TSecond> :EventArgs,IDisposable
{
//实现IEquatable<string>接口方法
public bool Equals(string other)
{
return false;
}
}
对于接口和基类型约束可以进行交换,基于这种特性,可以将指定的接口与实现分离,将为不同类型生成相同的签名的方法封装到一个接口中。无法在声明类型时指定其实现了该接口。
以上是主要讲解了分部类型的创建和使用方式,接下来我们再来了解一下分部方法的相关知识。
对于分部方法的相关概念,在前面介绍分部类型时已经做了介绍,分部方法的创建和使用与分部类型类似。分部方法有一个特点:任何对未实现的分部方法的调用,都会被编译器移除。
分部方法的声明与抽象方法的申明类似,只需要使用partial修饰符提供签名而无须任何实现。实现也需要partial修饰符进行修饰。有如下代码:
SegmentType1.cs:
partial class SegmentType
{
public SegmentType()
{
SegmentTypeStart();
Console.WriteLine("分部方法解析...");
SegmentTypeEnd();
}
partial void SegmentTypeStart();
partial void SegmentTypeEnd();
}
SegmentType2.cs
partial class SegmentType
{
partial void SegmentTypeStart()
{
Console.WriteLine("分部方法开始...");
}
}
在分部方法中,由于方法可能不存在,所以分部方法返回类型必须声明为void,且不能获取out参数。分部方法必须是私有的,但是是静态的或是泛型。
二.C#分部类型和分部方法的特点:
上面介绍了分部类型和分部方法的定义、创建和使用方式,在这里主要介绍一下分部方法和分部类型的特点。分部类型主要连接设计器和其他代码生成器。利用分部类型模型,代码生成器可以拥有自由的操作文件,或者只要它愿意可以每次都重写整个文件。
某些代码生成器还可以选择不生成任何C#文件,而是等到构建进行的时候再生成。代码生成器的应用比较的广泛,比如Web服务器代理、ORM工具生成配置文件等等。对于在ORM工具的应用有如下图:
分部类型在其他方面也有比较多的使用,分部类型可以辅助我们进行重构。(重构的第一步就是将比较大的类型分成较小的类,很多的关联的内容首先就可以分割为在两个或多个文件上存放的分部类型。)
分部类型也可以帮助我们进单元测试。
分部方法能在手动创建的文件中指定某种行为,并在自动生成的文件中使用该行为。
分部类型和分部方法是一个语言特性,在这里给出一个使用了分部类型的项目。https://github.com/fiidau/Phasing-Utility
对于分部类型和分部方法的介绍还有很多,在本文中只是做了一个简单的介绍,分布类型的使用也是比较的广泛,可以极大的提升我们的代码质量。希望本文对大家有所帮助。