Разделяемые классы и методы (Руководство по программированию в C#)

Имеется возможность разделить определение класса или структуры, интерфейса или метода между двумя или более исходными файлами.Каждый исходный файл содержит определение типа или метода, и все части объединяются при компиляции приложения.

Разделяемый класс

Существует несколько ситуаций, при которых желательно разделение определения класса:

  • При работе над большими проектами распределение класса между различными файлами позволяет нескольким программистам работать с ним одновременно.

  • При работе с использованием автоматически создаваемого источника код можно добавлять в класс без повторного создания файла источника.Система Visual Studio использует этот подход при создании форм Windows Forms, программы оболочки веб-службы и т.д.Можно создать программу, использующую эти классы, без необходимости изменения файла, созданного системой Visual Studio.

  • Чтобы разделить определение класса, используйте модификатор ключевого слова partial, как показано ниже:

public partial class Employee
{
    public void DoWork()
    {
    }
}

public partial class Employee
{
    public void GoToLunch()
    {
    }
}

Ключевое слово partial указывает на то, что другие части класса, структуры или интерфейса могут быть определены в пространстве имен.Все части должны использовать ключевое слово partial.Для формирования окончательного типа все части должны быть доступны во время компиляции.Все части должны иметь одинаковые специальные возможности, например public, private и т.д.

Если какая-либо из частей объявлена абстрактной, то весь тип будет считаться абстрактным.Если какая-либо из частей объявлена запечатанной, то весь тип будет считаться запечатанным.Если какая-либо из частей объявляет базовый тип, то весь тип будет наследовать данный класс.

Все части, указывающие базовый класс, должны быть согласованы друг с другом, а части, не использующие базовый класс, все равно наследуют базовый тип.Части могут указывать различные базовые интерфейсы, и окончательный тип будет реализовывать все интерфейсы, перечисленные во всех разделяемых объявлениях.Любые члены класса, структуры или интерфейса, объявленные в разделяемом объявлении, доступны для всех остальных частей.Окончательный тип представляет собой комбинацию всех частей, выполненную во время компиляции.

ПримечаниеПримечание

Модификатор partial нельзя использовать для объявлений делегата или перечисления.

В следующем примере показано, что вложенные типы могут быть разделяемыми, даже если тип, в который они вложены, не является разделяемым.

class Container
{
    partial class Nested
    {
        void Test() { }
    }
    partial class Nested
    {
        void Test2() { }
    }
}

При компиляции атрибуты определений разделяемого типа объединяются.В качестве примера рассмотрим следующие объявления:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

Они эквивалентны следующим объявлениям:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

Следующие элементы объединяются изо всех определений разделяемого типа:

  • XML-комментарии;

  • интерфейсы;

  • атрибуты параметров универсального типа;

  • атрибуты классов;

  • members

В качестве примера рассмотрим следующие объявления:

partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }

Они эквивалентны следующим объявлениям:

class Earth : Planet, IRotate, IRevolve { }

wa80x488.collapse_all(ru-ru,VS.110).gifОграничения

Имеется несколько правил, которые необходимо выполнять при работе с определениями разделяемого класса:

  • Все определения разделяемого типа, являющиеся частями одного и того же типа, должны изменяться с использованием модификатора partial.Например, следующие объявления класса приведут к появлению ошибки:

    public partial class A { }
    //public class tcA { }  // Error, must also be marked partial
    
  • Модификатор partial должен находиться непосредственно перед ключевыми словами class, struct или interface.

  • В определениях разделяемого типа могут присутствовать вложенные разделяемые типы, что показано в следующем примере:

    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
    partial class ClassWithNestedClass
    {
        partial class NestedClass { }
    }
    
  • Все определения разделяемого типа, являющиеся частями одного и того же типа, должны быть определены в одной сборке и в одном модуле (EXE-файл или DLL-файл).Разделяемые определения не могут находиться в разных модулях.

  • Имя класса и параметры универсального типа должны соответствовать всем определениям разделяемого типа.Универсальные типы могут быть разделяемыми.Все объявления разделяемого типа должны использовать одинаковые имена параметров в одном и том же порядке.

  • Приведенные ниже ключевые слова необязательно должны присутствовать в определении разделяемого типа, но если они присутствуют в одном определении разделяемого типа, то не должны конфликтовать с ключевыми словами, указанными в других определениях того же разделяемого типа:

Пример 1

wa80x488.collapse_all(ru-ru,VS.110).gifОписание

В следующем примере поля и конструктор класса CoOrds объявлены в одном определении разделяемого класса, а член PrintCoOrds — в другом определении разделяемого класса.

wa80x488.collapse_all(ru-ru,VS.110).gifКод

public partial class CoOrds
{
    private int x;
    private int y;

    public CoOrds(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class CoOrds
{
    public void PrintCoOrds()
    {
        Console.WriteLine("CoOrds: {0},{1}", x, y);
    }

}

class TestCoOrds
{
    static void Main()
    {
        CoOrds myCoOrds = new CoOrds(10, 15);
        myCoOrds.PrintCoOrds();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
// Output: CoOrds: 10,15

Пример 2

wa80x488.collapse_all(ru-ru,VS.110).gifОписание

В следующем примере показано, что можно также разработать разделяемые структуры и интерфейсы.

wa80x488.collapse_all(ru-ru,VS.110).gifКод

partial interface ITest
{
    void Interface_Test();
}

partial interface ITest
{
    void Interface_Test2();
}

partial struct S1
{
    void Struct_Test() { }
}

partial struct S1
{
    void Struct_Test2() { }
}

Разделяемые методы

Разделяемый класс или структура могут содержать разделяемый метод.Одна часть класса содержит сигнатуру метода.В той же или в другой части можно определить дополнительную реализацию.Если реализация не предоставлена, то метод и все вызовы метода удаляются во время компиляции.

Разделяемые методы позволяют разработчику одной части класса определить метод, схожий с событием.Разработчик другой части класса может решить, реализовывать этот метод или нет.Если метод не реализован, то компилятор удаляет сигнатуру метода и все вызовы этого метода.Вызовы метода, включая любые результаты, которые могли бы произойти от оценки аргументов в вызовах, не имеют эффекта во время выполнения.Таким образом, любой код в разделяемом классе может свободно использовать разделяемый метод, даже если реализация не предоставлена.Во время компиляции и выполнения программы не возникнут никакие ошибки, если метод будет вызван, но не реализован.

Разделяемые методы особенно полезны для настройки автоматически созданного кода.Они позволяют зарезервировать имя и сигнатуру метода, чтобы автоматически созданный код мог вызвать метод, а разработчик мог сам решить, реализовывать этот метод или нет.Как и разделяемые классы, разделяемые методы позволяют организовать совместную работу автоматически созданного кода и кода, созданного человеком, без дополнительных затрат во время выполнения.

Объявление разделяемого метода состоит из двух частей: определения и реализации.Они могут находиться в разных частях или в одной и той же части разделяемого класса.Если объявление реализации отсутствует, то компилятор оптимизирует код, удаляя как объявление определения, так и все вызовы метода.

// Definition in file1.cs
partial void onNameChanged();

// Implementation in file2.cs
partial void onNameChanged()
{
  // method body
}
  • Объявления разделяемого метода должны начинаться с контекстно-зависимого ключевого слова partial, а метод должен возвращать значение типа void.

  • Разделяемые методы могут иметь параметры ref, но не могут иметь параметры out.

  • Разделяемые методы неявно имеют модификатор private и поэтому не могут иметь модификатор virtual.

  • Разделяемые методы не могут иметь модификатор extern, поскольку наличие тела определяет, выполняется ли их определение или реализация.

  • Разделяемые методы могут иметь модификаторы static и unsafe.

  • Разделяемые типы могут быть универсальными.Ограничения помещаются в ту часть обяъвления разделяемого метода, где находится определение, и могут дополнительно повторяться в разделе реализации.Имена параметров и типов параметров необязательно должны совпадать в объявлении реализации и в объявлении определения.

  • Можно использовать делегат в качестве определенного и реализованного разделяемого метода, но его нельзя использовать в качестве разделяемого метода, который только определен.

Спецификация языка C#

Дополнительные сведения см в Спецификация языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

См. также

Ссылки

Классы (Руководство по программированию на C#)

Структуры (Руководство по программированию на C#)

Интерфейсы (Руководство по программированию в C#)

разделяемый (тип) (Справочник по C#)

Основные понятия

Руководство по программированию на C#