Разделяемые классы и методы (Руководство по программированию в 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 { }
Ограничения
Имеется несколько правил, которые необходимо выполнять при работе с определениями разделяемого класса:
Все определения разделяемого типа, являющиеся частями одного и того же типа, должны изменяться с использованием модификатора 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
Описание
В следующем примере поля и конструктор класса CoOrds объявлены в одном определении разделяемого класса, а член PrintCoOrds — в другом определении разделяемого класса.
Код
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
Описание
В следующем примере показано, что можно также разработать разделяемые структуры и интерфейсы.
Код
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#)