C#中的部分类方法解释

24

我很难理解部分类方法的用法。

你能提供一个与LINQ或数据库无关的例子吗?

部分类方法和在WinForms中编写后台代码时使用方法是否相同?如果我们使用一个方法,则它会被编译,但如果不使用,则编译器会将其删除。这正确吗?

3个回答

35

当你有一个局部类时,可以在一个文件中定义方法的签名,并在另一个文件中实现该方法。这就是部分类的一种方式。

因此,在一个文件中,您可以有:

partial class Foo
{
    partial void Bar();  // no implementation

    public void DoSomething()
    {
        // do some stuff...
        Bar();    // this will be removed if Bar isn't implemented in another partial class
        // do something else...
    }
}

而在另一个里,你有

partial class Foo
{
    partial void Bar()
    {
        // do something...
    }
}

这样,第一个文件可以调用Bar而不必担心是否实现了Bar。如果没有在某个地方实现Bar,则会删除对它的调用(从这里):

部分类方法使类的一个部分的实现者能够定义方法,类似于事件。类的另一部分的实现者可以决定是否实现该方法。如果未实现该方法,则编译器将删除该方法签名和所有对该方法的调用。对该方法的调用(包括在调用中评估参数可能产生的任何结果)在运行时没有任何影响。因此,即使未提供实现,部分类中的任何代码都可以自由使用部分类方法。如果调用该方法但未实现,也不会导致编译时或运行时错误。

Partial方法必须返回void,否则在未实现该方法的情况下删除所有方法调用是不安全的:

部分类方法声明必须以上下文关键字partial开头,而且该方法必须返回void

与部分类一样,主要用途是与生成的代码一起工作:

部分类方法特别适用于自定义生成的代码。它们允许保留方法名称和签名,以便生成的代码可以调用该方法,但开发人员可以决定是否实现该方法。与部分类类似,部分类方法使由代码生成器创建的代码和由人类开发人员创建的代码能够在没有运行时成本的情况下协同工作。

因此,您可能会生成调用部分类方法(在生成的代码中未定义实现)的代码,您可以自由扩展该部分类并实现该部分类方法,如果您想/需要这样做。

谢谢马克,但你能提供一个例子来说明它有用吗?这就是我不明白的地方。 - Johnson
与部分类一样,主要用途是让生成的代码和您自己的代码协同工作,而不会使重新生成的代码破坏您的内容。 - Matt Burland
1
我了解部分类(Partial classes),但是部分方法(Partial methods)是什么呢?有哪些使用部分方法的例子? - Johnson

7

以下是我在自己的编程中使用的示例... 作为一名教师,我经常向我的同学提供代码示例。然而,我希望他们能够逐步实现他们的编码项目,随着时间的推移使它变得越来越复杂。更具体地说,假设我向他们提供了一个运行菜单以测试和驱动他们需要实现的类的代码。在第一步中,菜单很简单。然后随着每个新步骤的到来,越来越多的菜单项被添加以测试更多的类功能。因此,最初,我向他们提供一个单独的文件来实现一个简单的菜单,然后随着他们向完整解决方案前进,我会提供更多的文件来驱动和检查他们的新编程。可以这样做:

// --- File MenuStep1.cs ---
partial class Menu
{
    // This array is populated with more and more items at every new steps
    readonly List<MenuItem> MenuItems = new List<MenuItem>();

    public void Show()
    {
        // Code to show menu here
    }

    // Suppose we have a Main here, but that's not necessary
    public static void Main()
    {
        new Menu().Show();   
    }

    // These are hooking methods to add menu items later
    partial void InitStep2();
    partial void InitStep3();
    partial void InitStep4();

    public Menu()
    {
        InitStep1();
        InitStep2();
        InitStep3();
        InitStep4();
    }

    void InitStep1()
    {
        // Code that adds menu items, but only for step 1
    }
}

请注意,由于部分类InitStep2、3和4尚未定义,它们将不会被调用(甚至不会被编译)。稍后我会提供自动扩展菜单的文件,并为它们提供以下内容:
// --- File MenuStep2.cs ---
partial class Menu
{
    partial void InitStep2()
    {
        // Code that adds more menu items
    }
}

,

// --- File MenuStep3.cs ---
partial class Menu
{
    partial void InitStep3()
    {
        // Code that adds more menu items
    }
}

等等。


多好的使用示例。 - ABS
我无法理解这里如何应用partial,因为所有方法都有不同的名称。 - Johnny Wu
1
@JohnnyWu 如果以 InitStep2 方法为例,由于它在 MenuStep1 文件中被声明为 partial,因此可以在 Menu 方法中使用和调用,而无需先定义,因此一开始会被忽略。该定义稍后可以在第二个文件 MenuStep2 中提供。 - Frederic

-1

作为 Matt Burlands的回答的补充, Johnsons在该回答的评论中提出跟进问题:

我从未自己创建过它们,但我想到了一些小用途:

  • 使用部分类方法创建类似抽象类或接口的东西。基本上,这种方式可以有“可选方法”,使得能够删除方法实现而不必删除它们各自的调用并最终重新实现
  • 使用部分类方法能够在同一个基础上构建具有不同实现的多个项目。您可以拥有一个构建过程,允许您在不同的部分类中选择不同的实现。 “基类”将具有方法签名,“实现类A.cs”和“实现类B.cs”将具有不同的实现。这样,您可以例如创建Develop-Test-和Releaseimplementations或User1-User2和User3 implementations。很酷的事情是您不必在运行时区分这些内容。相反,您将能够分发已经指定到那个程度的“干净”版本。

我还想指出一些可能是替代部分方法实现你所尝试达成的目标的差异。

  • 事件 - 部分方法可以像事件一样使用。如果它们没有被实现,它们将被忽略(甚至不在编译结果中)。但与事件有所不同。虽然您可以为一个事件拥有多个处理程序,但只能实现一次部分方法!
  • 抽象类和接口 - 部分类/方法可以像抽象类一样使用,而无需实现方法并将其保留为空。如果您知道这将经常发生在给定的抽象类中(首先检查您的架构,显然可能存在缺陷),则可以改用部分方法。

另一种用途可能是为某人提供基本功能。您可以通过我所谓的“自下而上”方式来实现,这意味着您创建了某些内容,人们将其用作基础,构建在其之上,像使用工具一样使用它。或者您可以提供“自上而下”的服务。也就是说,您已经实现了组件如何协同工作,但其他人可能会定义这些组件在内部确切地执行什么操作,例如:我想建一个桌子,我已经实现了它是一个带有四条腿的盘子,但我让用户选择腿的形式。这通常与生成的代码一起使用,在一个类中编写生成的和自制的代码,但在不同的.cs文件中。

注意

话虽如此,这些可能不是实现这些目标的最佳方法。有多种方法可以完成这些任务,无需使用部分类,而且可能更适合您想要做的事情。但也许这些会给你一些关于如何使用部分类的想法。这真的取决于您需要做什么,但了解部分类的工作原理可能对将来有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接