Partial class c что это
Перейти к содержимому

Partial class c что это

  • автор:

Partial class c что это

Классы могут быть частичными. То есть мы можем иметь несколько файлов с определением одного и того же класса, и при компиляции все эти определения будут скомпилированы в одно.

Например, определим в проекте два файла с кодом. Не столь важно как эти файлы будут называться. Например, PersonBase.cs и PersonAdditional.cs. В одном из этих файлов (без разницы в каком именно) определим следующий класс:

public partial class Person < public void Move() < Console.WriteLine("I am moving"); >>

А в другом файле определим следующий класс:

public partial class Person < public void Eat() < Console.WriteLine("I am eating"); >>

Таким образом, два файла в проекте содержит определение одного и того же класса Person, которые содержат два разных метода. И оба определенных здесь класса являются частичными. Для этого они определяются с ключевым словом partial .

Partial classes in C#

Затем мы можем использовать все методы класса Person:

class Program < static void Main(string[] args) < Person tom = new Person(); tom.Move(); tom.Eat(); Console.ReadKey(); >>

Частичные методы

Частичные классы могут содержать частичные методы. Такие методы также опреляются с ключевым словом partial . Причем определение частичного метода без тела метода находится в одном частичном классе, а реализация этого же метода — в другом частичном классе.

Например, изменим выше определенные классы Person. Первый класс:

public partial class Person < partial void Read(); public void DoSomething() < Read(); >>
public partial class Person < partial void Read() < Console.WriteLine("I am reading a book"); >>

В первом классе определен метод Read() . Причем на момент определения первого класса неизвестно, что представляет собой этот метод, какие действия он будет выполнять. Тем не менее мы знаем список его параметров и можем вызвать в первом классе.

Второй класс уже непосредственно определяет тело метода Read() .

class Program < static void Main(string[] args) < Person tom = new Person(); tom.DoSomething(); >>

Стоит отметить, что по умолчанию к частичным методам применяется ряд ограничений:

  • Они не могут иметь модификаторы доступа
  • Они имеют тип void
  • Они не могут иметь out-параметры
  • Они не могут иметь модификаторы virtual, override, sealed, new или extern

Если же они не соответствуют какому-то из этих ограничений, то для них должна быть предоставлена реализация. Как, например, в следующем примере частичные методы применяют модификатор public :

// первая реализация класса и его методов public partial class Person < public partial void Read(); public void DoSomething() < Read(); >> // вторая реализация класса и его методов public partial class Person < public partial void Read() < Console.WriteLine("I am reading a book"); >>

Programming stuff

Частичные классы (partial classes) (*) – это весьма простая конструкция языка C#, которая позволяет определить один класс в нескольких файлах (**). Это далеко не rocket science, но существует пара интересных сценариев их применения, которые являются не столь очевидными с первого взгляда. Но об этом позже, а начнем мы лучше с простого объяснения, что это такое и с чем его едят.

Общие сведения

Давайте вспомним старые добрые дни C# 1.0, когда спецификация языка была вдвое тоньше, возможностей языка было на порядок меньше, да и не было никаких LINQ-ов и всех остальных dynamic-ов (и вопросов на собеседовании, соответственно, тоже). Но даже тогда компилятор языка старался скрасить наши с вами серые будни и усердно выполнял всякую унылую работу, но делал он это не втихаря, путем генерации всяких там анонимных классов или методов, а путем генерации C# кода с помощь дизайнеров. И все бы ничего, но с этим подходом зачастую приходили и некоторые проблемы, которые, в основном сводились к ярому желанию разработчика расширить этот код и к ярому сопротивлению этого кода от подобного ручного вмешательства. Другими словами, внесение любых изменений в автосгенерированный код всегда вели к беде, ибо тут же прибивались компилятором при повторной генерации.

В те далекие дни существовало два простых способа борьбы с этой проблемой. Первый способ активно применялся, например, дизайнером Windows Forms, когда весь сгенерированный код формы помещался в отдельный регион, изменять который было чревато, а весь остальной пользовательский код располагался в оставшейся части файла (и, соответственно, класса). Другой подход наиболее часто применялся при работе с датасетами (да, это ORM для бедных, точнее и не ORM вовсе, но это уже и не важно), когда для расширения функционала нужно было создать класс-наследник и добавить в него весь необходимый дополнительный функционал.

Не сложно догадаться, что ни один из этих вариантов нельзя назвать очень уж удачным, так что не удивительно, что разработчики языка решили решить (во как!) эту проблему и предоставили возможность реализовывать один класс в нескольких файлах. В этом случае одним файлом ведает компилятор и творит с ним всяческие непотребства, ну а со вторым чем-то схожим занимается девелопер.

Итак, вот простой пример:

// CustomForm.cs
// За «содержимое» этого файла отвечает пользователь
public partial class CustomForm : Form
public CustomForm()
InitializeComponent();
>
>
// CustomForm.Designer.cs
// А вот этим файлом «занимается» дизайнер форм
partial class CustomForm
// Код, сегенерированный компилятором
private void InitializeComponent()
< >
>

Обратите внимание, что только в одном файле указан наследник текущего класса (в данном случае, класс Form), и область видимости этого класса (ключевое слово public); это упрощает контроль этих аспектов пользователем, оставляя код, сгенерированный компилятором в нетронутом виде. Кроме того, как не сложно заметить, класс CustomForm все еще остается одним классом, что позволяет вызывать функции, определенные в одном файле (в данном случае, это функция InitializeComponent) из другого файла.

Частичные классы и выделение абстракций

Не пугайтесь страшного названия, rocket science в этой заметке так и не появится, просто более удачного названия подобрать не смог. Дело все в том, что частичные классы умеют делать нечто не совсем интуитивно понятное с первого взгляда. А именно, объявления частичных классов совпадать не должны, это значит, что в одном файле вы можете «объявить» реализацию классом некоторого интерфейса, а во втором файле – реализовать этот интерфейс, путем определения всех его методов (хотя можно часть методов реализовать в одном файле, а часть в другом; я думаю, что идея понятна):

// IFoo.cs
// Простой интерфейс, с одним единственным методом
interface IFoo
void DoSomething();
>
// Foo.cs
// В этом файле мы объявляем, что класс Foo реализует интерфейс IFoo
partial class Foo : IFoo
< >
// Foo.IFoo.cs
// А в этом файле, мы этот интерфейс реализуем
partial class Foo
public void DoSomething() < >
>

И что в этом такого, скажете вы? Да, в общем-то, ничего особенного, но иногда это может очень здорово помочь при работе с автосгенерированным кодом. Давайте представим, что у нас есть некоторые сгенерированные компилятором классы (будь-то, классы, генерируемые по XSD, классы-сущности базы данных или что-то еще), и так уж вышло, что каждый из этих, совершенно не связанных между собой классов, содержит некоторую общую функциональность в виде набора свойств или методов, которые, в общем-то, делают одно и то же. Но поскольку все они генерируются компилятором, у вас (и у нас, кстати, тоже) нет возможности обрабатывать их обобщенным образом с помощью некоторого базового класса или интерфейса, в результате ваш код (и наш иногда тоже) начинает обрастать неприглядными конструкциями следующего вида:

ProcessType1(objectOfType1);
ProcessType2(objectOfType2);

Но, на самом деле, вам никто не мешает создать собственный интерфейс, который будет содержать всю общую функциональность, в виде свойств или методов, а затем просто добавить этот интерфейс к вашему определению частичного класса, не трогая при этом сгенерированный код. Тогда, если в каждом сгенерированном классе содержится свойство Name, вы можете добавить интерфейс IName со свойством Name и обрабатывать эти классы одним методом:

// IName.cs
// Вводим собственный интерфейс, содержащий общие свойства и методы
// некоторого семейства автосгенерированных классов.
interface IName
string Name < get; >
>

// AutogeneratedObject.Designer.cs
// Автосгенерированный код содержит свойство Name.
partial class AutogeneratedObject1
public string Name < get; private set; >
>

// AutogeneratedObject.cs
// Добавляем свой вклад в «абстракцию» этого класса.
// Теперь он реализует интерфейс IName, хотя настоящая реализация
// этого интерфейса находится в автосгенерированном коде.
partial class AutogeneratedObject1 : IName
<>

// Где-то еще.cs
// Теперь мы можем обрабатывать любое количество автоматически сгенерированных
// типов, до тех пор пока они содержат нашу «выделенную» абстракцию в виде интерфейса IName.
void ProcessIName(IName name) <>

Частичные классы в юнит-тестировании

Чисто теоретически применение частичных классов не ограничивается автоматически сгенерированным кодом. Это самая обычная возможность языка программирования, и никто не мешает вам разбивать ваши собственные классы на несколько файлов. Почему «чисто теоретически»? Потому что, в большинстве случаев, если вы видите преимущества от использования частичных классов для реализации ваших собственных бизнес-сущностей, возникает некоторое подозрение, что эти самые сущности делают слишком много и, скорее всего, будет не лишним разбить их на несколько составляющих. (Хотя, нужно признать, из этого правила бывают и исключения.)

И хотя создание крупных классов в подавляющем большинстве случаев ни к чему хорошему не приводит, наличие достаточно увесистых классов юнит-тестов, в несколько раз превосходящих по объему тестируемые классы, дело обычное. Даже для небольшого класса может быть достаточно много сценариев тестирования, которые вполне можно сгруппировать по некоторому признаку (например, по некоторому аспекту поведения или чему-то в этом роде). В этом случае, мы можем разбить юнит-тест на несколько классов, и тогда придется запускать каждый из них независимо, а можем разбить один юнит-тест на несколько файлов с «частичными» классами. В этом случае, мы сможем запускать все тесты за раз, поскольку у нас будет всего один класс, но зато мы избавимся от громадных файлов. (Да, я знаю о наличии регионов, но мне подход с частичными классами нравится больше).

// FooTest.cs
// «Основная часть» класса FooTest, в данном случае предназначенная для тестирования
// метода DoSomething
[TestClass]
public partial class FooTest
[TestMethod]
public void DoSomethingTest()
// Тестирование метода DoSomething
Console.WriteLine(«DoSomethingTest»);
>
>
// Foo.ConstructorTest.cs
// «Часть» класса FooTest, отвечающая за тестирование конструктора класса Foo
partial class FooTest
[TestMethod]
public void ConstructorTest()
// Тестирование конструктора класса Foo
Console.WriteLine(«ConstructorTest»);
>
>

«Объединение» частичных классов в Solution Explorer-е

Внимательный разработчик наверняка давно уже заметил, что наша с вами любимая среда разработки, когда речь заходит об автоматически сгенерированном коде, умеет хитрым образом «объединять под одним крылом» частичные классы. Это выражается в том, что в Solution Explorer-е файлы, сгенерированные компилятором, находится «под» основным файлом, с которым работает разработчик. Но раз так, то наверняка мы сможем применять эту же технику для группировки наших собственных частичных классов.

И действительно, для этого достаточно немного поменять файл проекта и для зависимого файла добавить элемент с именем DependentUpon:

Compile Include="Foo.cs" />
Compile Include="Foo.IFoo.cs">
DependentUpon>Foo.csDependentUpon>
Compile>

Помимо ручного редактирования файла проекта, можно порыться в Visual Studio Gallery и поискать расширение с подобной функциональностью. Как минимум одно расширение, с незамысловатым названием VSCommands 2010 поддерживает группировку нескольких файлов именно таким образом. После установки этого расширения в контекстном меню в Solution Explorer-е появятся дополнительные пункты меню “Group Items” и “Ungroup Items”, соответственно. Но не зависимо от того, каким именно способом вы будете «объединять» файлы, результат будет следующий (рисунок 1):

PartialClasses

Рисунок 1 – Группировка файлов в Solution Explorer

Заключение

Ну вот, пожалуй, и все. Частичные классы – это действительно весьма простая возможность языка C#, которая в подавляющем большинстве случаев используется совместно с дизайнерами и автоматически генерируемым кодом. Но, тем не менее, существуют и другие интересные контексты использования этой возможности, которые могут быть не столь очевидными с первого взгляда.

(*) Да, как правильно заметили в комментариях, частичными бывают не только классы, но еще и структуры и интерфейсы. Так что все, что здесь говорится о классах, применимо еще и для структур с интерфейсами.

(**) Вообще-то, частичные классы могут объявляться и в одном файле:

//Foo.cs
partial class Foo < >

//Foo.cs
partial class Foo < >

Но вот польза в таком объявлении весьма сомнительна.

Зачем нужны частичные методы, если можно сделать так(см. ниже)?

Я смотрю(смотрел?) на функционал частичных методов как на то, что вне зависимости того, где находится тело реализации метода, мы можем использовать метод и в первом, и во втором классе, что удобно при командной работе, когда нам, например, нужно в классе B использовать метод класса A(я знаю, что одинаковое название должно быть, просто назвал так для удобства), для чего, как я думал раньше, нужно не только сделать частичные классы, а и методы, но, походу, хватит только того, что я сделаю классы частичными.
Тогда скажите, пожалуйста, и объясните, для чего конкретно нужны частичные методы. Насчёт автогенерируемого кода и что они могут использоваться там я слышал, но нифига не понял, что это за «автогенерируемый код», может, пока что просто не дошёл до работы с ним; если вам удобно, то расскажите про это, а также про другие случаи, когда могут понадобиться частичные методы.

  • Вопрос задан более двух лет назад
  • 372 просмотра

Комментировать
Решения вопроса 1

AVollane

Начинающий C# разработчик

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

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

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

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

Разделенные classes в Си Шарп

Класс в объектно-ориентированном программировании – модель, необходимая для создания объектов определенного типа. Она будет описывать структуру соответствующих компонентов программного кода (набор полей и их первоначальное состояние), а также формировать алгоритмы (методы и функции) для работы с ними. Классы необходимы для введения абстрактных типов данных в программный код. Они определяют не только интерфейс, но и реализацию для всех своих экземпляров.

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

Разделяемые классы – это…

В C# можно провести разделение класса между несколькими исходными файлами. Каждый документ с исходным кодом будет содержать часть (part) определения class. Во время компиляции все его составляющие будут объединяться.

The partial class C# помогает работать над одним классом сразу нескольким людям. Это особо актуально, когда речь идет о крупном проекте и большом количестве разработчиков.

Чтобы воспользоваться соответствующим компонентом нужно использовать ключевое слово partial. Оно поможет разделить определение class.

Особенности

The partial – слово, которое указывает на то, что иные части class могут быть объявлены в имеющемся пространстве имен. Если нужно создать the partial class, недостаточно использовать соответствующий ключ. Дополнительно придется запомнить следующие особенности:

  1. Если хотя бы в одной части установлено объявление abstract, то и финальный тип окажется in the same. То же самое касается sealed.
  2. Если в части рассматриваемого элемента объявлен базовые класс, финальный тип унаследует его.
  3. Любой член, объявленный в the partial class, доступен остальным его parts.
  4. Все части the partial должны быть включены в одно и то же пространство имен.

Модификатор the partial недоступен при объявлении делегатов, а также возможных перечислений. У всех переменных в них должны быть одинаковые модификаторы доступа.

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

You can use in the partial classes the partial методы. Одна из частей имеющегося класса включает в себя сигнатуру метода. Остальная – может быть включает в ней же или в другой. Если реализация не предоставлена, метод и все его вызовы удаляются при компиляции.

Здесь рекомендуется запомнить следующее:

  • для задания all the partial methods используется ключевое слово «partial»;
  • в качестве типа возвращаемого значения устанавливается void;
  • у the partial methods неявный тип – private;
  • соответствующие методы не могут иметь тип virtual.

Теперь можно рассмотреть несколько наглядных примеров. Они помогут более подробно разобраться в изучаемом направлении. А еще – наглядно продемонстрируют то, как работает a class и a partial methods.

Высота и ширина

Первый пример – это приложение под названием HeightWeightInfo. В качестве результата его работы используется вывод в консоль информации о высоте и ширине. Внутри проекта будет находиться файл File1.cs, который имеет разделенный class Record. В нем определены целочисленные переменные – h и w. Здесь же реализован метод/конструктор Record. Он отвечает за присваивание переменным значений.

File1. cs выглядит так:

namespace HeightWeightInfo < class File1 < >public partial class Record < private int h; private int w; public Record(int h, int w) < this.h = h; this.w = w; >> >

Второй документ будет называться File2.cs. Он включает в себя точно такой же класс Records. Внутри него будет размещаться метод PrintRecord. Он отвечает за вывод в консоль значений переменных h и w:

namespace HeightWeightInfo < class File2 < >public partial class Record < public void PrintRecord() < Console.WriteLine("Высота:"+ h); Console.WriteLine("Ширина:"+ w); >> >

В данном проекте есть еще и метод the main. Он будет иметь следующую форму представления:

namespace HeightWeightInfo < class Program < static void Main(string[] args) < Record myRecord = new Record(10, 15); myRecord.PrintRecord(); Console.ReadLine(); >> >

Здесь можно увидеть объект класса myRecord. В виде его параметров выступят значения h и w, которые будут определяться в File1.cs. Метод PrintRecord будет вызван объектом myRecord. Он объявлен в File2.cs. Ключевое слово keyword позволяет объединить атрибуты the class, объявленного в разных файлах, в единое целое.

The partial в C Sharp может быть полезен в нескольких случаях:

  1. При формировании проекта, в котором задействовано больше одного разработчика. The partial позволяет работать совместно над одним и тем же классом.
  2. Когда необходимо дополнить или отредактировать класс без повторного создания исходного файла, который автоматически генерируется IDE.

Также стоит изучить еще один наглядный пример of the C# code, который поможет лучше понять разделенные методы языка.

Пример для методов

В качестве примера можно взять the partial class Car, который объявлен в File1.cs. В нем будет содержаться три метода:

  • InitializeCar();
  • BuildRim();
  • BuildWheels().

Среди них будет объявлен the partial class InitializeCar. В виде программы этот фрагмент выглядит так, как показано ниже.

public partial class Car < partial void InitializeCar(); public void BuildRim() < >public void BuildWheels()

Проект включает в себя документ File2. Он поддерживает BuildEngine и InitializeCar. Реализация метода разделена на 2 части: сначала происходит объявление в файле File1, затем – выполнение в file2.

Как быстро освоить тему

Для более быстрого и качественного изучения C#, его классов и методов, а также иных возможностей, рекомендуется закончить специализированные дистанционные компьютерные курсы. Пример – от OTUS.

На них помогут с нуля освоить любой язык разработки, фреймворк или инновационную IT-профессию. Пользователи получат шанс влиться в информационные технологии в срок от нескольких месяцев до года. Им предлагается широкий выбор специальностей и направлений – разрешено остановиться на одном или нескольких вариантах.

К преимуществам онлайн-курсов относят:

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

В конце обучения всем ученикам будут выданы электронные сертификаты. С их помощью удастся подтвердить приобретенный спектр навыков и умений документально и полностью официально.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *