Страницы

Поиск по вопросам

воскресенье, 2 февраля 2020 г.

Partial методы в C#

#c_sharp


Какое практическое применение есть для partial методов? 

Например,

partial class A
{
    partial void OnSomethingHappened(string s);
}

partial class A
{
    partial void OnSomethingHappened(String s)
    {
        Console.WriteLine("Something happened: {0}", s);
    }
}




Partial Method C#
    


Ответы

Ответ 1



Если вопрос именно про про практическое применение - то оно достаточно ограничено тем, что partial методы могут возвращать только void. Т.е. систему "архитектор объявляет методы, разработчик реализует" на partial не построишь. Есть два основных применения: Упрощение подключения обработчиков, Например, в global.asax в ASP.NET, достаточно объявить метод с нужным именем: protected void Application_Start(object sender, EventArgs e) и его автоматически прицепит к обработчику события Start. Если вы попытаетесь сделать похожий механизм в своем кодогенераторе - то будет достаточно объявить все возможные "обработчики" как partial методы, и вызвать их в соответствующих местах. Если компилятор найдет реализацию обработчика - он оставит вызов. Если нет - просто вырежет. Отладочные вызовы для написания юнит-тестов, особенно для случаев бросания исключений. Например, вам нужно написать тест на обработку ошибки подключения к Redis, причем именно на ошибки сокета. Инкапсулировть всю работу с сокетами в класс-обертку только ради тестового бросания исключений - дорого и долго. Можно сделать точечную отладочную вставку в живом коде: internal sealed partial class PhysicalConnection : IDisposable, ISocketCallback { partial void OnDebugAbort(); //... SocketMode ISocketCallback.Connected(Stream stream, TextWriter log) { //... // disallow connection in some cases OnDebugAbort(); //... } } И написать реализацию, которая будет существовать только в отладочном варианте: #if DEBUG internal partial class PhysicalConnection { partial void OnDebugAbort() { if (!Multiplexer.AllowConnect) { throw new RedisConnectionException(ConnectionFailureType.InternalFailure, "debugging"); } } #endif

Ответ 2



Когда есть partial class, сигнатуру методов можно определить в одном файле, а реализацию в другом. Например В одном файле может быть: partial class Foo { partial void Bar(); // без реализации public void DoSomething() { // что-то делаем... Bar(); // Это может быть удалено, если `Bar` нигде не будет реализован // делаем что-от еще... } } А в другом файле: partial class Foo { partial void Bar() { // что-то делаем... } } Это позволяет вызывать Bar в первом файле не беспокоясь реализован он где-нибудь или нет. Если Bar так и не был нигде реализован, то все его вызовы будут удалены во время компиляции (отсюда): Partial методы позволяют реализующему одну часть класса определять методы, похожие на события. Реализующий вторую часть класса решает, будет ли он реализовывать метод или нет. Если метод не был реализован, то компилятор удалит сигнатуру метода и все его вызовы. Вызовы метода, включая любые результаты, которые могут получиться при вычисление аргументов при вызове будут проигнорированы в run time. Поэтому любой код в partial class может свободно использовать partial method, даже если он не будет реализован. В результате, если метод был вызван без реализации, не будет никаких compile-time или run-time ошибок. Как и в случае с partial classes, основное применение - работа со сгенерированным кодом: Partial method особенно полезны при настройке сгенерированного кода. Они позволяют зарезервировать имя и сигнатуру метода, чтобы сгенерированный код мог вызвать метод, но разработчик может сам решить реализовывать ли этот метод. Подобно partial classes, partial method позволяют совмещать сгенерированный код и код написанный разработчиком без затрат в run-time. Так что может быть сгенерированный код, вызывающий partial method (определенный без реализации в сгенерированном коде) и разработчик сам решает хочет ли он / нужно ли ему расширять partial class и реализовывать partial method. Перевод ответа @Matt Burland

Ответ 3



Partial классы могут быть удобны, когда вы работаете с какой-нибудь внешней библиотекой или фреймворком и хотите иметь возможность расширить возможности классов, реализованных в библиотеке( или фреймворке), но при этом оставить сам исходный код библиотеки без изменения (например в ситуации когда исходный код этой библиотеки подтягивается в ваш проект в виде git submodule и вы не хотите вести отдельную ветку для своего проекта). Для этого вы можете создать отдельный файл в своем проекте с partial объявлением существующего класса и добавить в него нужную вам функциональность. Также, если вы сами работаете над какой-либо библиотекой, построенной вокруг одного класса (на манер singlton), вам возможно захочется физически разделить функциональность класса на несколько частей, для удобства навигации и редактирования, при это не разделяя его на 2 различных подкласса (довольно вырожденный пример, однако имеет право на существование). Partial методы могу быть удобны для реализации декорации объекта, опционального добавления функциональности, например валидации каких-либо полей, либо добавления пре- или пост-действий, что может быть также удобно при работе с классами сторонних библиотек или фреймворков.

Комментариев нет:

Отправить комментарий