在C#3.0中如何使用部分方法?

时间:2020-03-05 18:47:10  来源:igfitidea点击:

我已经阅读了最新的Clanguage规范中的部分方法,所以我了解这些原理,但是我想知道人们实际上是如何使用它们的。是否有部分设计方法可以受益于特定的设计模式?

解决方案

回答

代码生成是它们存在的主要原因之一,也是使用它们的主要原因之一。

编辑:即使该链接是特定于Visual Basic的信息,相同的基本原理也与C#有关。

回答

我将它们视为轻量级事件。我们可以拥有一个可重用的代码文件(通常是自动生成的,但不是必须的),并且对于每个实现,只需处理我们在部分类中关心的事件即可。实际上,这就是在LINQ to SQL中使用它的方式(以及发明语言功能的原因)。

回答

部分方法在概念上与GoF模板方法行为模式(Design Patterns,p325)非常相似。

它们允许将算法或者操作的行为定义在一个地方,并在其他地方实现或者更改,从而实现可扩展性和自定义。我已经开始在C3.0中使用部分方法而不是模板方法,因为我认为代码更干净。

一个不错的功能是,未实现的部分方法在编译时不会产生运行时开销。

回答

这是C#.NET 3.0中部分类的最佳资源:http://msdn.microsoft.com/zh-cn/library/wa80x488(VS.85).aspx

我尝试避免使用局部类(Visual Studio为设计器文件创建的局部类除外;它们很棒)。对我来说,将一个类的所有代码放在一个地方更为重要。如果班级设计得很好并且代表一件事(单项责任原则),那么关于那件事的所有代码都应该放在一个地方。

回答

引入部分方法的原因与.Net 2中为什么存在部分类的原因类似。

子类是一种可以拆分为多个文件的类,编译器在运行时将它们全部构建为一个文件。

这样做的好处是,Visual Studio可以为部分类提供图形设计器,而编码人员可以在另一部分上使用图形设计器。

最常见的示例是表单设计器。开发人员大部分时间都不想手动定位按钮,输入框等。

  • 在.Net 1中,它是在#region块中自动生成的代码
  • 在.Net 2中,这些变成了单独的设计器类-表单仍然是一个类,它只是分成一个由开发人员编辑的文件和一个由表单设计者编辑的文件

这使两者的维护更加容易。合并更简单,并且VS表单设计者意外撤消编码人员的手动更改的风险较小。

在.Net 3.5中,引入了Linq。 Linq有一个DBML设计器来构建数据结构,并生成自动代码。

这里额外的一点是需要提供开发人员可能想要填写的方法的代码。

随着开发人员将扩展这些类(带有额外的部分文件),他们在这里不能使用抽象方法。

另一个问题是,大多数情况下不会调用这些方法,而调用空方法是浪费时间。

空方法未优化出来。

因此,Linq生成空的局部方法。如果我们不创建自己的局部零件来完成它们,则Ccompiler只会对其进行优化。

这样它可以做到这一点,部分方法总是返回void。

如果创建新的Linq DBML文件,它将自动生成部分类,例如

[System.Data.Linq.Mapping.DatabaseAttribute(Name="MyDB")]
public partial class MyDataContext : System.Data.Linq.DataContext
{
    ...

    partial void OnCreated();
    partial void InsertMyTable(MyTable instance);
    partial void UpdateMyTable(MyTable instance);
    partial void DeleteMyTable(MyTable instance);

    ...

然后,在我们自己的部分文件中,可以扩展此内容:

public partial class MyDataContext
{
    partial void OnCreated() {
        //do something on data context creation
    }
}

如果我们不扩展这些方法,则会立即对其进行优化。

部分方法不能是公共的,因为它们必须在那里,其他类才能调用。如果我们编写自己的代码生成器,我会发现它们很有用,但是否则它们仅对VS设计器真正有用。

我之前提到的示例是一种可能性:

//this code will get optimised out if no body is implemented
partial void DoSomethingIfCompFlag();

#if COMPILER_FLAG
//this code won't exist if the flag is off
partial void DoSomethingIfCompFlag() {
    //your code
}
#endif

另一个潜在的用途是,如果我们有一个庞大而复杂的类散布在多个文件中,则可能需要在调用文件中部分引用。但是,我认为在这种情况下,我们应该首先考虑简化类。