Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Можно разделить определение класса, структуры, интерфейса или члена по двум или нескольким исходным файлам. Каждый исходный файл содержит раздел определения типа или члена, а все части объединяются при компиляции приложения.
Разделяемые классы
Существует несколько ситуаций, когда желательно разделение определения класса.
- Объявление класса по отдельным файлам позволяет нескольким программистам одновременно работать над ним.
- Вы можете добавить код в класс, не создавая исходный файл, который включает автоматически созданный источник. Visual Studio использует этот подход при создании форм Windows Forms, кода оболочки веб-службы и т. д. Можно создать код, который использует эти классы, без необходимости изменения файла, созданного в Visual Studio.
- Генераторы источников могут создавать дополнительные функциональные возможности в классе.
Чтобы разделить определение класса, используйте модификатор частичного ключевого слова. На практике каждый частичный класс обычно определяется в отдельном файле, что упрощает управление и расширение класса с течением времени.
В следующем Employee
примере показано, как класс может быть разделен на два файла: Employee_Part1.cs и Employee_Part2.cs.
// This is in Employee_Part1.cs
public partial class Employee
{
public void DoWork()
{
Console.WriteLine("Employee is working.");
}
}
// This is in Employee_Part2.cs
public partial class Employee
{
public void GoToLunch()
{
Console.WriteLine("Employee is at lunch.");
}
}
//Main program demonstrating the Employee class usage
public class Program
{
public static void Main()
{
Employee emp = new Employee();
emp.DoWork();
emp.GoToLunch();
}
}
// Expected Output:
// Employee is working.
// Employee is at lunch.
Ключевое слово 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. Однако если оба объявления частичного члена включают примечания, будут включены только комментарии от реализующего члена.
- интерфейсы
- атрибуты параметров универсального параметра
- атрибуты классов
- члены
В качестве примера рассмотрим следующие объявления:
partial class Earth : Planet, IRotate { }
partial class Earth : IRevolve { }
Они эквивалентны следующим объявлениям:
class Earth : Planet, IRotate, IRevolve { }
Ограничения
При работе с определениями частичного класса существует несколько правил:
- Все определения разделяемого типа, являющиеся частями одного типа, должны изменяться с использованием типа
partial
. Например, следующие объявления класса приведут к появлению ошибки:public partial class A { } //public class A { } // Error, must also be marked partial
-
partial
Модификатор может отображаться непосредственно перед ключевым словомclass
илиstruct
interface
. - В определениях разделяемого типа могут присутствовать вложенные разделяемые типы, что показано в следующем примере:
partial class ClassWithNestedClass { partial class NestedClass { } } partial class ClassWithNestedClass { partial class NestedClass { } }
- Все определения разделяемого типа, являющиеся частями одного и того же типа, должны быть определены в одной сборке и в одном модуле (EXE-файл или DLL-файл). Частичные определения не могут охватывать несколько модулей.
- Имя класса и параметры универсального типа должны соответствовать всем определениям разделяемого типа. Универсальные типы могут быть разделяемыми. Все объявления разделяемого типа должны использовать одинаковые имена параметров в одном и том же порядке.
- Следующие ключевые слова для определения частичного типа являются необязательными, но если они присутствуют в одном определении частичного типа, то же самое должно быть указано в другом частичном определении для того же типа:
- общественный
- частный
- защищено
- внутренний
- абстрактный
- запечатанный
- базовый класс
- модификатор new (вложенные части)
- универсальные ограничения
Дополнительные сведения см. в разделе Ограничения параметров типа.
Примеры
В следующем примере поля и конструктор Coords
класса объявляются в одном определении разделяемого класса (Coords_Part1.cs
), а PrintCoords
метод объявляется в другом определении разделяемого класса (Coords_Part2.cs
). Это разделение показывает, как частичные классы можно разделить на несколько файлов для упрощения обслуживания.
// This is in Coords_Part1.cs
public partial class Coords
{
private int x;
private int y;
public Coords(int x, int y)
{
this.x = x;
this.y = y;
}
}
// This is in Coords_Part2.cs
public partial class Coords
{
public void PrintCoords()
{
Console.WriteLine("Coords: {0},{1}", x, y);
}
}
// Main program demonstrating the Coords class usage
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
В следующем примере показано, что можно также разработать разделяемые структуры и интерфейсы.
partial interface ITest
{
void Interface_Test();
}
partial interface ITest
{
void Interface_Test2();
}
partial struct S1
{
void Struct_Test() { }
}
partial struct S1
{
void Struct_Test2() { }
}
Частичные члены
Частичный класс или структуру может содержать частичный элемент. Одна часть класса содержит сигнатуру члена. В той же или в другой части можно определить реализацию.
Реализация не требуется для частичного метода, если подпись подчиняется следующим правилам:
- Объявление не включает модификаторы доступа. Метод имеет
private
доступ по умолчанию. - Тип возвращаемого значения —
void
. - Ни один из параметров не имеет
out
модификатора. - Объявление метода не может содержать ни одного из следующих модификаторов:
Метод и все вызовы метода удаляются во время компиляции при отсутствии реализации.
Любой член, который не соответствует всем этим ограничениям, включая конструкторы, свойства, индексаторы и события, должен предоставлять реализацию. Эта реализация может быть предоставлена генератором источника. Частичные свойства нельзя реализовать с помощью автоматически реализованных свойств. Компилятор не может различать автоматическое свойство и объявление частичного свойства.
Начиная с C# 13, объявление реализации для частичного свойства может использовать свойства с поддержкой полей для определения объявления реализации. Резервное свойство поля предоставляет краткий синтаксис, в котором field
ключевое слово обращается к компилятору, синтезированному поле резервной копии для свойства. Например, можно написать следующий код:
// in file1.cs
public partial class PropertyBag
{
// Defining declaration
public partial int MyProperty { get; set; }
}
// In file2.cs
public partial class PropertyBag
{
// Defining declaration
public partial int MyProperty { get => field; set; }
}
Вы можете использовать field
либо в методе get
set
доступа, либо в обоих вариантах.
Внимание
Ключевое field
слово — это предварительная версия функции в C# 13. Для использования контекстного ключевого <LangVersion>
слова необходимо использовать .NET 9 и задать preview
элемент field
в файле проекта.
Следует тщательно использовать функцию field
ключевого слова в классе с именем field
поля. Новое field
ключевое слово тенирует поле с именем field
в области доступа к свойствам. Можно изменить имя переменной field
или использовать @
маркер для ссылки на field
идентификатор как @field
. Дополнительные сведения см. в спецификации компонента для ключевого field
слова.
Частичные члены позволяют разработчику одной части класса объявить члена. Реализующий другую часть класса может определить этот элемент. Существует два сценария, в которых это разделение полезно: шаблоны, создающие стандартный код и генераторы источников.
- Код шаблона: шаблон резервирует имя и подпись метода, чтобы созданный код мог вызвать метод. Эти методы придерживаются ограничений, которые позволяют разработчику решить, следует ли реализовать этот метод. Если метод не реализован, компилятор удаляет сигнатуру метода и все вызовы метода. Вызовы метода, включая любые результаты, которые могли бы произойти от оценки аргументов в вызовах, не имеют эффекта во время выполнения. Поэтому любой код в частичном классе может свободно использовать частичный метод, даже если реализация не предоставлена. Если метод вызывается, но не реализуется, не возникает никаких ошибок во время компиляции или времени выполнения.
- Генераторы источников: генераторы источников предоставляют реализацию для членов. Разработчик может добавить объявление члена (часто с атрибутами, считываемыми генератором источника). Разработчик может написать код, вызывающий эти элементы. Генератор источника выполняется во время компиляции и обеспечивает реализацию. В этом сценарии ограничения для частичных членов, которые могут быть не реализованы, часто не следуют.
// Definition in file1.cs
partial void OnNameChanged();
// Implementation in file2.cs
partial void OnNameChanged()
{
// method body
}
- Объявления частичных элементов должны начинаться с частичного контекстного ключевого слова.
- Частичные подписи членов в обеих частях частичного типа должны соответствовать.
- Частичный член может иметь статические и небезопасные модификаторы.
- Частичный член может быть универсальным. Ограничения должны совпадать с определением и реализацией объявления члена. Имена параметров и типов не должны совпадать в объявлении реализации, как и в определяемом.
- Делегат можно сделать делегатом к частичному методу, определенному и реализованном, но не к частичному методу, который не имеет реализации.
Спецификация языка C#
Дополнительные сведения см. в разделе "Частичные типы " и частичные методы в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#. Новые функции для частичных элементов определяются в спецификациях функций для расширения частичных методов, частичных свойств и индексаторов, а также частичных событий и конструкторов.