C>Какая-то очень мутная фича. Решение крайне узкой задачи, которую можно решить другими методами. C>Или я то-то упускаю?
Имхо, это очень простая фича. По-сути, это всего лишь возможность разбить код класса на несколько файлов в рамках одной сборки.
А прикладное применение из того, что вспомнилось:
1. Разделение объемного класса на несколько файлов для удобства восприятия и поддержки: по функциональности (My class.cs, MyClass.Feature1.cs, MyClass.Fearure2.cs), по платформе (My class.cs, MyClass.net4x.cs, MyClass.netcore.cs), по каким-то иным критериям. Причем, конкретные файлы могут включаться в проект по каким-то условиям.
2. Расширение функционала автоматически сгенерированных классов без необходимости наследования (e.g EFCore db first, кодогенераторы API-клиентов по swagger/avro/protobuf спекам)
3. Кодогенерация реализации partial методов, объявленных пользователем (см. например, Riok.Mapperly).
C>А нафига, собственно, без необходимости наследования?
Ну а зачем заводить лишний уровень абстракции, если можно без него обойтись?
Скажем, в случае автогенерации HTTP-клиента, это может выглядеть вот так:
// Client.generated.cspartial class ApiClient {
public async Task SendRequest(HttpRequestMessage request) {
OnBeforeRequest(request);
// .. логика отправки запроса, получение ответа
OnAfterResponse(response);
}
partial void OnBeforeRequest(HttpRequestMessage request);
partial void OnAfterResponse(HttpRequestMessage response);
}
// И это дает возможность простой кастомизации запросов/ответов
// Client.Customization.cspartial class ApiClient {
partial void OnBeforeRequest(HttpRequestMessage request) {
request.Headers.Add("X-Header", "SomeValue");
}
}
Или взять другой пример — редактор форм в WinForms/WPF.
// MainWindow.xaml.cspublic partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Здесь располгается наш код (обработчики событий и т.п.)
}
// MainWindow.g.i.cs - автосгенерированый файлpublic partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {
// Здесь куча автосгенерированного кода по созданию, инициализации, настройке, позиционированиию компонентов,
// которые мы мышкой накидали в визуальном редакторе
}
Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, RushDevion, Вы писали:
RD>>Ну а зачем заводить лишний уровень абстракции, если можно без него обойтись?
C>Пц. А это ничего, что ради этого бзика пришлось заводить целую новую фичу языка, которая вероятно будет нужна 0.0001% рарзработчиков?
У нас в проекте есть, сами сделали зачем-то. А так когда одна часть класса автогенерированна, а вторая пишется программистом — то нормально.
Здравствуйте, Qulac, Вы писали:
Q>А так когда одна часть класса автогенерированна, а вторая пишется программистом — то нормально.
Да не, у меня другие вопросы.
1. А что, им никак нельзя было обойтись без поддержки в языке?
2. Какому числу людей вообще нужна эта фича? Сколько людей пишет кодогенерацию на C#, на весь мир? 10 тысяч? Думаю, намного меньше.
C>Пц. А это ничего, что ради этого бзика пришлось заводить целую новую фичу языка, которая вероятно будет нужна 0.0001% рарзработчиков?
Ну, если верить https://dotnetcrunch.in/csharp-version-history-features, то patial types появились в C# 2.0, а partial methods в C# 3.0.
И, как мне кажется, не последнюю роль в этом сыграли как раз WinForms и ASP.NET Web forms, где появилась насущная потребность разделять автогенерируемую и пользовательскую части классов.
А дальше с появлением source generator'ов эта фича вышла на новый уровень:
// Генерация кода конечного автомата на C#
[GeneratedRegex("cat|dog", RegexOptions.IgnoreCase, "en-US")]
private static partial Regex CatOrDogGeneratedRegex();
// Генерация кода маппинга
[Mapper]
public partial class CarMapper
{
public partial CarDto CarToCarDto(Car car);
}
Здравствуйте, Codealot, Вы писали:
RD>>появилась насущная потребность разделять автогенерируемую и пользовательскую части классов.
C>Тот же вопрос. Эту задачу нельзя было решить без специальной поддержки в языке?
А у меня встречный вопрос: почему ты вдруг взвился именно на эту фичу?
По-моему, она достаточно безобидная.
А так — можно было и без этого, конечно. Можно было через #include заставить всё реально собираться в одном файле. Можно было вообще всех заставить писать напрямую на ассемблере Где граница?
Здравствуйте, netch80, Вы писали:
N>А у меня встречный вопрос: почему ты вдруг взвился именно на эту фичу?
Я уже написал две причины.
N>А так — можно было и без этого, конечно. Можно было через #include заставить всё реально собираться в одном файле. Можно было вообще всех заставить писать напрямую на ассемблере Где граница?
Не доводи до абсурда. Можно легко решить эту задачу простейшими средствами языка.
Здравствуйте, Codealot, Вы писали:
N>>А у меня встречный вопрос: почему ты вдруг взвился именно на эту фичу?
C>Я уже написал две причины.
Я перечитал всю тему и не понял, какие это "две причины". Ты говорил, что оно нужно <очень малой доле> разработчиков. Сочту это за половину причины. Где ещё одна?
Повтори, пожалуйста, а то понять таки сложно.
N>>А так — можно было и без этого, конечно. Можно было через #include заставить всё реально собираться в одном файле. Можно было вообще всех заставить писать напрямую на ассемблере Где граница?
C>Не доводи до абсурда. Можно легко решить эту задачу простейшими средствами языка.
RD>>появилась насущная потребность разделять автогенерируемую и пользовательскую части классов.
C>Тот же вопрос. Эту задачу нельзя было решить без специальной поддержки в языке?
А предложи как именно это сделать без поддержки в языке на примере того же WinForms.
public partial class MainWindow : Window
{
public MainWindow()
{
// В австосгенеренной partial-части создается код вида
// private Button _button1;
//
// _button1 = new Button();
// _button1.Position = new Position(...);
InitializeComponent();
}
// Здесь располгается наш код (обработчики событий и т.п.)
}
Как сделать то же самое, не нарушая инкапсуляцию класса MainWindow (т.е. не отдавая наружу все эти private _button1)
и не вводя лишние сущности, вроде MainWindowInitializer и т.п.?
Как при этом сделать так, чтобы пользовательский код не ломал автосгенеренный и наоборот?
Начнем с того, что это у тебя не partial methods.
RD>Как сделать то же самое, не нарушая инкапсуляцию класса MainWindow (т.е. не отдавая наружу все эти private _button1)
Делаешь их protected, генеришь базовый класс, наследуешься от него.
RD>и не вводя лишние сущности, вроде MainWindowInitializer и т.п.?
Почему нет, собственно? Опять сектантские поверья?
C>Вот не надо петросянить. Вопрос был про одну фичу, а ты придумал про другую, хотя и связанную.
Так это ж не я придумал. Это эти... которые из микрософта.
А я просто теоретизирую, как исторически могла возникнуть необходимость в partial types.
А partial methods, имхо, запилили чисто за компанию. Типа, а чё прикольно и сделать несложно. А давайте прикрутим? А давайте!
Здравствуйте, RushDevion, Вы писали:
RD>А я просто теоретизирую, как исторически могла возникнуть необходимость в partial types.
Про типы еще более-менее, хотя все равно фича довольно сомнительная.
RD>А partial methods, имхо, запилили чисто за компанию. Типа, а чё прикольно и сделать несложно. А давайте прикрутим? А давайте!
Здравствуйте, Codealot, Вы писали:
C>Или я то-то упускаю?
Класс можно вынести в шаред проджект, подключить его к другим проектам, в которых сделать свою реализацию partial methods специфичную для данной сборки.
Здравствуйте, Codealot, Вы писали:
C>Какая-то очень мутная фича. Решение крайне узкой задачи, которую можно решить другими методами. C>Или я то-то упускаю?
Вы ее просто не умеете готовить, в partial можно абсолютно просто всунуть любой генереный код, а смысловой оставить, при этом снаружи класс будет выглядеть как обычно.
Наследование тут вообще неуместно в принципе, т.к. потомков может быть в принципе много
Но вся нагрузка ключевого слова partial склеить два файла.
MS это использовал как в вин формах и было очень удобно, так по моему и в WPF, можно наверное DTO, протобафа нагенерить ну и прочее.
Здравствуйте, Codealot, Вы писали:
C>Твоя незамутненная гордость тривиальными знаниями.
Ты на протяжении всего топика спрашиваешь "нафига?". Вариант с автогенерацией тебя не удовлетворил, я предложил другое применение.
Причем тут моя гордость и мои знания я хз
Здравствуйте, rFLY, Вы писали:
FLY>Ты на протяжении всего топика спрашиваешь "нафига?". Вариант с автогенерацией тебя не удовлетворил, я предложил другое применение. FLY>Причем тут моя гордость и мои знания я хз
Переформулирую: нафига это было нужно на уровне языка, а не просто библиотеки? Что там были за нерешаемые проблемы?
Ну и заодно другие сообщения почитай.
Здравствуйте, Codealot, Вы писали:
C>Переформулирую: нафига это было нужно на уровне языка, а не просто библиотеки?
Каким образом ты это на уровне библиотеки собрался решать?
C>Что там были за нерешаемые проблемы?
А какие проблемы решает var или оператор +=? Зачем его ввели, когда можно написать a = a + b?
C>Ну и заодно другие сообщения почитай.
Читал, но так и не понял причину твоего хейта к этим методам.
Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, RushDevion, Вы писали:
RD>>Ну а зачем заводить лишний уровень абстракции, если можно без него обойтись?
C>Пц. А это ничего, что ради этого бзика пришлось заводить целую новую фичу языка, которая вероятно будет нужна 0.0001% рарзработчиков?
Когда мы переделылавали UI, нам майковские советчики посоветовали WPF с модной тогда аритектурой MVC. Дали курс, и, вместе с нами, где-то полгода делали каркас нашей непростой системы с кучей паармеров и сценариев использования.
Controller, втолне ожидаемо превратился в God Object, который эти соватчики нам разбросали в partial class не только по разным файлам, но даже по поддиректориям, с иерархией и именами, соответствующим каким — либо сценариям.
Это потом уже все признали какой это отстой и все ринулись всё переделывать на MVVM. Но GodController живёт, и умереть у него не выйдет.
Здравствуйте, Codealot, Вы писали:
C>Какая-то очень мутная фича. Решение крайне узкой задачи, которую можно решить другими методами. C>Или я то-то упускаю?
Здравствуйте, Codealot, Вы писали:
RD>>Ну а зачем заводить лишний уровень абстракции, если можно без него обойтись?
C>Пц. А это ничего, что ради этого бзика пришлось заводить целую новую фичу языка, которая вероятно будет нужна 0.0001% рарзработчиков?
Ты видишь суслика — нет. А он есть. Сейчас в связи с Native AOT Source Generator прикручивают везде где нужно изменять поведение классов на этапе компиляции.
Здравствуйте, RushDevion, Вы писали:
RD>А partial methods, имхо, запилили чисто за компанию. Типа, а чё прикольно и сделать несложно. А давайте прикрутим? А давайте!
Хотя, больше похоже, что кто-то сделал эту фичу чисто под себя. Под свою задачу и религиозные бзики.
Здравствуйте, Serginio1, Вы писали:
S> Ты видишь суслика — нет. А он есть. Сейчас в связи с Native AOT Source Generator прикручивают везде где нужно изменять поведение классов на этапе компиляции.
Здравствуйте, Serginio1, Вы писали:
S>Это фича нужна прежде всего для SourceGenerators.
Вполне очевидно, что оно было сделано для кодогенерации.
Тот же вопрос, что и раньше — что мешало использовать для решения этой задачи существующие средства языка?
S>> Ты видишь суслика — нет. А он есть. Сейчас в связи с Native AOT Source Generator прикручивают везде где нужно изменять поведение классов на этапе компиляции.
C>И где там хоть одно упоминание partial methods?
Здравствуйте, Codealot, Вы писали:
S>>Это фича нужна прежде всего для SourceGenerators.
C>Вполне очевидно, что оно было сделано для кодогенерации. C>Тот же вопрос, что и раньше — что мешало использовать для решения этой задачи существующие средства языка?
Ну единственное решение это абстрактный класс.
Но иногда проще вместо генерации наследника, проще использовать существующий класс, а специализацию уже делать при компиляции.
По сути это аналог шаблонов С++, но с интеллисенсе и статической типизацией.
и солнце б утром не вставало, когда бы не было меня
Вопрос, а как определяется порядок компиляции partial методов? Из какого partial метода код
раньше\позже? Я это понимаю так, что в конце все partial методы превращаются в один метод, не partial.
Как это происходит?
ЗЫ: Про partial классы безусловно знаю, ибо долго работал с winforms, а вот про методы ничего не знаю,
не доводилось применять.
S>Вопрос, а как определяется порядок компиляции partial методов? Из какого partial метода код S>раньше\позже? Я это понимаю так, что в конце все partial методы превращаются в один метод, не partial.
Если я правильно понял вопрос, то речь о чем-то таком?
Это не скомпилируется. Будет ошибка: "A partial method may not have multiple defining declarations"
S>Как это происходит?
Очень просто. Сводим все partial-файлы для типа в один, заменяя partial definition на partial declaration.
И, кстати, в отличие от virtual/override, partial работает только в рамках текущей сборки (текущего проекта).
Здравствуйте, Codealot, Вы писали:
S>> Нет. Но там куча методов генерится.
C>То есть, без partial methods прекрасно можно обойтись?
Не прекрасно. Нужно вводить абстрактность. А это проблемы с инлайнингом.
и солнце б утром не вставало, когда бы не было меня
S>> Ну единственное решение это абстрактный класс.
C>Думаю, можно и другие найти. Опять же, чем плох абстрактный класс?
Тем что виртуальные методы плохи для инлайнинга и избавления от виртуальности VMT S>> По сути это аналог шаблонов С++, но с интеллисенсе и статической типизацией.
C>И с очень ограниченной областью применения.
Поясни в чем ограниченность? Написать свой Source Generator не можешь?
Распространяй компоненты в исходниках.
Опять же если тебе не нужны partial methods используй абстрактные в чем проблема. Больше инструментов это хорошо!
Ну и вообще надо смотреть на эволюцию SG. Сейчас практически partial methods не нужны если они уже прописаны в SG и парсер их видит.
Но бывает, что SG не хватает данных и нужны методы заглушки для интеллисенса и статической типизации.
Но опять методы можно формировать, даже если и нет данных. Обычные заглушки.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Тем что виртуальные методы плохи для инлайнинга и избавления от виртуальности VMT
Экономия на спичках. В случае тех же винформ, у них уже наворочено столько уровней абстракции, что эффект от "экономии" в инициализаторе не разглядеть даже в микроскоп.
S> Поясни в чем ограниченность?
В том, что кроме генераторов, других применений у этих методов нет. В отличии от шаблонов.
S> Больше инструментов это хорошо!
Если задачу можно было решить универсальными средствами, а вместо них сделали средства для одной узко заданной задачи — это совсем не хорошо.
Здравствуйте, Codealot, Вы писали:
S>> Тем что виртуальные методы плохи для инлайнинга и избавления от виртуальности VMT
C>Экономия на спичках. В случае тех же винформ, у них уже наворочено столько уровней абстракции, что эффект от "экономии" в инициализаторе не разглядеть даже в микроскоп.
Там все упирается в Paint, по сравнению с ним лишняя косвенность копейки. S>> Поясни в чем ограниченность?
C>В том, что кроме генераторов, других применений у этих методов нет. В отличии от шаблонов.
Шаблон это и есть генератор текста. Как раз С++ щеголяли ими по сравнению с дженериками.
Просто по шаблону текст генерится во время компиляции, а для SG во время проектирования и можешь посмотреть реальный код! S>> Больше инструментов это хорошо!
C>Если задачу можно было решить универсальными средствами, а вместо них сделали средства для одной узко заданной задачи — это совсем не хорошо.
Я с тебя хренею. Вот те кто занимается SG это хорошо. А тем кто не занимается тем похрену.
И это задача совсем не узкая! Расширяются инструменты.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Там все упирается в Paint, по сравнению с ним лишняя косвенность копейки.
Можно и так сказать. В любом случае, так сильно волноваться из-за абстрактных методов в кодогенераторе — экономия на спичках.
S>Шаблон это и есть генератор текста. Как раз С++ щеголяли ими по сравнению с дженериками.
Вовсе нет, в C++ все намного сложнее.
S> Я с тебя хренею. Вот те кто занимается SG это хорошо. А тем кто не занимается тем похрену. S>И это задача совсем не узкая! Расширяются инструменты.
Просто ты никак не поймешь. Я не спрашиваю "как эту фичу можно приспособить". Я спрашиваю "почему именно так, а не иначе".
Здравствуйте, Codealot, Вы писали:
C>Просто ты никак не поймешь. Я не спрашиваю "как эту фичу можно приспособить". Я спрашиваю "почему именно так, а не иначе".
Ну вот ту разрабатываешь свой класс. Тебе нужно применить к нему какую то рутину используя кучу генераторов https://github.com/amis92/csharp-source-generators
Для римера PropertyChanged.SourceGenerator
А там нужен какой то метод помеченный для генерации. И тебе надо сначала создать абстрактный класс, на основании которого сгенерируется новый класс.
Еще раз в самом начале SG не так хорошо генерировал и подхватывались сгенеренные файлы.
Поэтому partial methods нужны прежде всего, что бы не ждать генерацию.
Немерлисты критикуют SG что макросы лучше https://rsdn.org/article/nemerle/NemerleStingFormating.xml
Здравствуйте, Serginio1, Вы писали:
S>Еще раз в самом начале SG не так хорошо генерировал и подхватывались сгенеренные файлы. S>Поэтому partial methods нужны прежде всего, что бы не ждать генерацию.
Что мешает создать абстрактный метод и реализовать его в сгенеренном коде?
Здравствуйте, Codealot, Вы писали:
S>>Еще раз в самом начале SG не так хорошо генерировал и подхватывались сгенеренные файлы. S>>Поэтому partial methods нужны прежде всего, что бы не ждать генерацию.
C>Что мешает создать абстрактный метод и реализовать его в сгенеренном коде?
Зачем городить лишний класс? Тебе бы все усложнить. НЕ ХОЧУ! Мне как раз partial methods нравятся.
Но опять же сейчас надобность в них не актуальна. SG значительно оптимизировали.
Вот так как нельзя SG модифицировать существующий код override нужен. Но проще использовать существующие методы с генерацией новых.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Зачем городить лишний класс? Тебе бы все усложнить. НЕ ХОЧУ! Мне как раз partial methods нравятся.
Это у тебя уже религиозное. Классы практически ничего не стоят, пытаться их экономить — странная идея. А новая фича в языке — это как раз очень дорого.
S>>Зачем городить лишний класс? Тебе бы все усложнить. НЕ ХОЧУ! Мне как раз partial methods нравятся.
C>Это у тебя уже религиозное. Классы практически ничего не стоят, пытаться их экономить — странная идея. А новая фича в языке — это как раз очень дорого.
Это у тебя религиозное. На самом деле partial methods это уже анахронизмы. Проще уж интерфейс использовать, а не абстрактные классы.
Как я тебе показывал примеры, прямо в описании метода ты можешь использовать сгенеренные свойства, методы итд.
Не нужно никаких partial. Просто уже SG должен существовать.
Ничего дорого нет. А вот лишние действия с двумя классами точно.
Изначально был partial method только void, без ref параметров. Нужен был для T4.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Codealot, Вы писали:
RD>>Ну а зачем заводить лишний уровень абстракции, если можно без него обойтись?
C>Пц. А это ничего, что ради этого бзика пришлось заводить целую новую фичу языка, которая вероятно будет нужна 0.0001% рарзработчиков?
Эта фича появилась в те времена, когда почти 100% UI делалось мышом, итд. Почти каждая ваканся была про WinForms, WPF
Вообще, фича крайне удобна для любой кодогенерации
Здравствуйте, Serginio1, Вы писали:
S> Не совсем. Иногда сложно читать код в разных файлах. Так для удобства чтения небольшого класса видеть все определения partial очень удобны.
Здравствуйте, Codealot, Вы писали:
P>>Вообще, фича крайне удобна для любой кодогенерации
C>Точно так же можно было использовать virtual.
Неудобно — это плохо работает с несколькими файлами, больше 2х — сиди и думай, что от чего наследуется, сущности плодятся и всегда нужна реализация, хоть какая нибудь.
Здравствуйте, Codealot, Вы писали:
S>> Не совсем. Иногда сложно читать код в разных файлах. Так для удобства чтения небольшого класса видеть все определения partial очень удобны.
C>Они у тебя и так будут в разных файлах.
Реализация будет в разных файлах, а объявление partial в основном.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Codealot, Вы писали:
S>> Реализация будет в разных файлах, а объявление partial в основном.
C>И что тебе мешает сделать так же с базовым классом?
Зачем мне 2 класса вместо одного? Зачем плодить сущности?
Проблема виртуальности в том, что тяжело читать код.
То есть видишь метод, но реально переопределяет этот метод 10 классов.
И ничем не лучше partial классов.
Чем abstract или интерфейс лучше partial?
Только тем, что тебе почему то не нравится partial? Мне очень нравится и не только мне.
Мне partial нужен только для быстрого понимания кода в небольших классах.
Там где классы большие partial methods и не нужен.
Вернее может он и нужен где то для T4, но для SG не нужен.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Codealot, Вы писали:
S>> Зачем мне 2 класса вместо одного? Зачем плодить сущности?
C>Классы экономить. Пц.
Зачем на пустом месте плодить классы?
то есть вместо partial method нужно еще создавать класс наследник с реализацией метода.
Ты батенька мазохист.
Еще раз partial method только для удобства чтения класса. Всё!
Могу и не писать или удалить без последствий.
SG и так сгенерит реализацию метода.
А вот с классом наследником так не получится!
S>>То есть видишь метод, но реально переопределяет этот метод 10 классов. C>Синтаксически, ничем не должно отличаться.
Синтаксически да, а реализация разная S>>И ничем не лучше partial классов. S>> Чем abstract или интерфейс лучше partial?
C>Тем, что решают ту же задачу и не нужно загромождать язык.
Вот именно, что абстракт и загромождают.
А partial расширяют. Но как видно тебе это не понять.
Например реально для C# важнее быстрое написание SG через макросы.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Codealot, Вы писали:
S>> Зачем на пустом месте плодить классы?
C>Реально пц. Классы не тот ресурс, который нужно экономить.
Экономить не надо, а вот читать сложнее.
Кроме того методы могут быть приватными или вообще методами класса внутри класса.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Codealot, Вы писали:
P>>Малеха пропустили, и ваш метод повис в воздухе.
C>Непонятно, что ты хотел сказать.
Вы предлагаете подробить класс на цепочку наследования, которую надо теперь мейнтейнить руками. Три файла — три класса. Ошибаетесь в имени, наследуете 3й от 1го и приплыли.
В случае с partial вы доопределяете метод ровно там, где это нужно. Эдакий плагин.
Теперь интереснее — покажите, как вы собираетесь ваш генеренный код инстанцировать из другого генеренного кода
Подробно — как генератор узнает, что через год вы допишете наследование и нужно будет инстанцировать тот а не этот.
В нашем случае все просто — new XxxComponent()
Или делаем метод-фабрику, который тоже partial.
В вашем случае надо городить огород — пилить целый слой поверх, все перенаследовать.
Здравствуйте, Codealot, Вы писали:
C>Какая-то очень мутная фича. Решение крайне узкой задачи, которую можно решить другими методами. C>Или я то-то упускаю?
очень удобная фича когда делаешь свой кодогенератор, когда есть автогенеренный класс и нужно немного расширить его функциональность, не создавая при этом виртуальных методов.
partial class, partial метод очень подходят для этого.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, okon, Вы писали:
O>>не создавая при этом виртуальных методов.
C>Зачем, собственно?
А зачем их собственно создавать, если можно без них? Посмотри например на реализации StronglyTypedId на sg, и расскажи как их реализовать при помощи виртуальных методов и что будет в этом случае с производительностью. Ну или посмотри на nswag openapi2csclient, который генерит http-клиента, готового к использованию, а если его надо расширить, то достаточно реализовать несколько partial методов без наследования и изменения имени класса.
Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, amironov79, Вы писали:
A>>А зачем их собственно создавать, если можно без них?
C>А зачем собственно создавать частичные методы, если можно без них?
Если тебя не удовлетворяют ответы из этой ветки, тогда лучше задать этот вопрос на гитхабе C#, там архитекторы языка обитают, они точно в курсе истинных причин
Здравствуйте, Codealot, Вы писали:
A>>А зачем их собственно создавать, если можно без них?
C>А зачем собственно создавать частичные методы, если можно без них?
Codealot не читатель. В свое время T4 и SG работали только в компайл тайме.
Поэтому и нужны были partial methods. Сейчас SG работает design-time поэтому partial methods не особо то и нужны.
Да для быстроты нужно кэшировать проверять изменения.
Можно для себя для удобочитаемости в маленьких классах добавлять partial methods.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, amironov79, Вы писали:
A>Если тебя не удовлетворяют ответы из этой ветки, тогда лучше задать этот вопрос на гитхабе C#, там архитекторы языка обитают, они точно в курсе истинных причин
Здравствуйте, Codealot, Вы писали:
C>Никто так и не смог внятно объяснить, почему нельзя было использовать просто виртуальные методы. Ну, кроме "не хочу их использовать вот и всё".
У меня до генераторов руки пока так и не дошли, так что возможно напишу глупость.
В моём понимании смысл в том, что пишешь:
class MyModel
{
public int Property {get; set;}
[ToGenerate]
public partial int ProcessingToInt(string arg);
[ToGenerate]
public partial float ProcessingToFloat(string arg);
}
генератор по понятному ему атрибуту найдёт этот не реализованный метод, получит прототип (название, входные параметры, возвращаемый тип данных, область видимости) и реализует нужное тело метода.
В итоге дальше спокойно создаёшь объекты классы MyModel и работаешь с ними, вызываешь сгенерированные методы как самописные.
Если partial заменить на abstract, то получится, что генератору нужно будет создать целый новый класс-наследник, где будет реализован этот метод.
А значит нужно потом создавать везде объекты не MyModel, а сгенерированного наследника MyModelGenerated, чтобы дёргать этот виртуальный метод, что не есть удобно.
Если менять на virtual, то не понятно как это должно работать. Ну, разве что можно пустую реализацию самому писать с throw new NotImplementedException(), а генератор отработает как для abstract с созданием наследника и теми же сопутствующими неудобствами.
Если я ошибаюсь и генераторы так не умеют, то непонятно зачем они такие нужны
Здравствуйте, Codealot, Вы писали:
C>В чем неудобства, собственно говоря? Тоже хочешь экономить классы?
В том, что писал класс A, а нужно создавать объект хз какого класса с хз каким названием.
Потом это всё в логах где-то будет маячить, в отладчике хз как с навигацией выйдет.
sealed класс не сделаешь.
Иногда бывает хочется закрыть конструкторы и выставить наружу фабричные методы, опять в пролёте.
Да и просто получается генератор должен не только метод собрать, но и продублировать все конструкторы, чтобы они base вызывали.
При наследовании получается нужно перебирать всю иерархию классов на предмет таких виртуальных методов,
чтобы генератор для всех наследников метод продублировал в его персонального наследника (если конечно в этом классе вручную никто метод не перегрузил и не реализовал).
Либо нужно будет самому везде наследоваться от сгенерированного класса, а не того, что сам писал,
а значит в уже существующую иерархию собрался добавить генерируемый метод — сиди все наследования переделывай, а это ещё может быть и в разных проектах.
А если в одном классе 2 разных генератора должны собрать по 2 метода, то сколько наследников будет?
Сначала один генератор своего наследника сделает с копиями конструкторов и двумя сгенерированными методами, а потом второй ещё одного наследника будет создавать?
Не видно ни одного преимущества такого варианта, как не видно и ни одного недостатка у варианта с partial.
Здравствуйте, karbofos42, Вы писали:
K>В том, что писал класс A, а нужно создавать объект хз какого класса с хз каким названием. K>Потом это всё в логах где-то будет маячить, в отладчике хз как с навигацией выйдет.
Тебе самому не смешно?
K>sealed класс не сделаешь.
С чего вдруг?
K>Иногда бывает хочется закрыть конструкторы и выставить наружу фабричные методы, опять в пролёте. K>Да и просто получается генератор должен не только метод собрать, но и продублировать все конструкторы, чтобы они base вызывали.
Ты сам себе противоречишь. Или одно, или другое.
K>Сначала один генератор своего наследника сделает с копиями конструкторов и двумя сгенерированными методами, а потом второй ещё одного наследника будет создавать?
Естественно, не нужно этого делать. Один наследник для всего сгенеренного кода.
Ладно, пара пойнтов у тебя есть. Но это всё проблемы писателей кодогенераторов, и вполне решаемые.
Также, наверно лучше использовать для этой задачи интерфейс, а не базовый класс.
C>Какая-то очень мутная фича. Решение крайне узкой задачи, которую можно решить другими методами.
Чтобы у 1 класса был отдельный генеримый файл и отдельный рукописный (для удобства восприятия истории изменений в source control).
И без необходимости создавать лишний уровень наследования (что привело бы к удвоению кол-ва классов).
Здравствуйте, Codealot, Вы писали:
C>С чего вдруг?
Как кодогенератор от sealed класса наследника сгенерирует, чтобы в нём реализовать виртуальный метод?
C>Ты сам себе противоречишь. Или одно, или другое.
Так в одном классе нужно так, в другом иначе. Оба варианта создают сложности для кодогенераторов.
C>Ладно, пара пойнтов у тебя есть. Но это всё проблемы писателей кодогенераторов, и вполне решаемые.
Так проблемы решались и до Source Generators в том же Fody.
Но это было сложно, мало желающих было в это погружаться, а генерации людям хотелось.
Вот упростили им это, чтобы пошло в народ.
Собственно, я бы у себя в рабочем проекте несколько моментов с радостью через генераторы сделал, чтобы избавиться от копипасты, но сидим на старой версии языка и .NET Framework.
C>Также, наверно лучше использовать для этой задачи интерфейс, а не базовый класс.
Зависит от задачи. Ради генерации событий PropertyChanged во ViewModel всё писать на интерфейсах — такое себе.
O>>И без необходимости создавать лишний уровень наследования (что привело бы к удвоению кол-ва классов). C>Кхм, ты тоже экономишь классы?
Однажды я наблюдал, как молодёжь переписала "по паттернам" некое моё изделие (стоявшее на продакшене лет 10):
Бизнес-логика осталась нетронутой, но коллстек удлиннился раз в 10 или 20, и все новые шаги заключались в перекладке данных между какими-то пустыми передаточными микросервисами, каждый из которых имел свою модель сущностей предметной области, и при получении переписывал данные поле-в-поле в свои классы, а при передаче — ещё раз в чужие. На вопрос, почему не задействовать везде одну и ту же модель классов Entity Framework, ахретекторы выдавали какой-то булшыт про разделение ответственностей и принципы солид. Функционал почти не поменялся, кол-во кода и время отладки любого пустякового вопроса возросли десятикратно, но премии и повышения (и вроде даже госнаграды) пролились на эту группу как из рога изобилия. Так что возможно ты прав, экономить классы не всегда полезно.
Здравствуйте, Codealot, Вы писали:
C>Здравствуйте, amironov79, Вы писали:
A>>Если тебя не удовлетворяют ответы из этой ветки, тогда лучше задать этот вопрос на гитхабе C#, там архитекторы языка обитают, они точно в курсе истинных причин
C>Там вовсе не небожители, как тебе кажется.
Но там больше шансов получить истинный ответ на волнующий тебя вопрос. На этом форуме уже человек 10 сказали, для чего они используют partial methods, что это чисто утилитарная вещь, и о фиософмких причинах их появления в языке никто не задумывался.
Здравствуйте, karbofos42, Вы писали:
K>Собственно, я бы у себя в рабочем проекте несколько моментов с радостью через генераторы сделал, чтобы избавиться от копипасты, но сидим на старой версии языка и .NET Framework.
.NET Framework не ограничивает выбор версии языка. С поднятием версии языка в проекте обычно никаких проблем не возникает.
Здравствуйте, amironov79, Вы писали:
A>.NET Framework не ограничивает выбор версии языка. С поднятием версии языка в проекте обычно никаких проблем не возникает.
Часть фич языка таки привязана к рантайму и не всё доступно на старых .NET Framework.
Ну, и у нас в проекте явно ограничение на версию языка прописано по различным причинам.
Здравствуйте, karbofos42, Вы писали:
K>Как кодогенератор от sealed класса наследника сгенерирует, чтобы в нём реализовать виртуальный метод?
Кодогенератор сам должен добавить sealed в этом случае.
K>Так в одном классе нужно так, в другом иначе. Оба варианта создают сложности для кодогенераторов.
Да, писателям кодогенераторов это действительно в некоторой степени усложнило бы жизнь.
K>Но это было сложно, мало желающих было в это погружаться, а генерации людям хотелось.
Этим и сейчас занимается крайне малое число людей.
K>Зависит от задачи. Ради генерации событий PropertyChanged во ViewModel всё писать на интерфейсах — такое себе.
А в чем собственно проблема, вынести декларации твоих событий из основного класса в интерфейс?