Comments 31
Очень круто. Разве что я всегда думал что шарпам в частности и дотнету в целом не достаёт строгости, и фичу с дефолтной реализацией в интерфейсах в C# 8 я воспринял с опаской. Тем паче всегда с ужасом и восхищением я смотрел на то как люди реализуют вещи вроде описанных в статье для чего-то кроме спортивного интереса.
Да поможет господь тем, кому придется поддерживать код на ваших трейтах.
А если серьезно, то очень хотелось бы подробнее узнать какая проблема/задача ( наверняка интересная и нетривиальная) привела к созданию вот этого.
Сам я рассматриваю и допускаю использование SG в своих проектах только в контексте генерации некоторых моделей для/из контрактов и как некую замену Reflection в плане увеличения производительности.
Но честно говоря не очень понятно за что вы голосуете — писать всё на чистом C#? Или использовать только широко распространнёные библиотеки? До того как они стали широкораспространнёными, тоже делали MVP и смотрели — взлетит идея или нет. Не сразу же все знаменитыми становились, ну или по крайней мере у них был бюджет, чтобы потратить на развитие.
А source generators сейчас как раз в идеальной стадии для экспериментов, попробовать что может получиться. Хорошие идеи приживутся, плохие отсеются.
Вот писать свой — другое дело.
У написание своего велосипеда должны быть причины. Одно дело, когда причина — так что нет аналогов или аналоги не очень удовлетворяют требованием. И совершенно другое, когда авторам велосипедов просто лень разбираться в чужом коде/подходе. Вот второй случай я и считаю самым неудачным для проекта в целом.
идеальной стадии для экспериментов
Microsoft выпустили джина из бутылки. Это очень мощный инструмент, неправильное применение которого на стадии экспериментов может превратить в будущем проекты в совершенно не поддерживаемое легаси.
И что до вопроса по C#, да я бы предпочел в будущем проекты, которые используют стандартные и широко зарекомендованные приемы, чем велосипеды, только в которые требуется дополнительное длительное погружение, а не в предметную область бизнеса.
Вот второй случай я и считаю самым неудачным для проекта в целом.Я может быть скажу крамольную мысль, но не все разработчики заботятся о том что «лучше» для проекта, особенно если проект сам по себе унылое г. И придумывают себе немного развлечений в виде написания инструментария, велосипедов и т.п.
Тем более что «лучше» для проекта — оно у всех разное, не дай бог ещё бизнес спросить, что же лучше, много нового для себя можно открыть.
Это очень мощный инструмент, неправильное применение которого на стадии экспериментов может превратить в будущем проекты в совершенно не поддерживаемое легаси.Опять же, не понятно какое у вас предложение? Запретить и не пущать? Понятно что будут рождены уродливые мутанты (вполне возможно что и этот проект один из них), но это как раз вполне ожидаемо.
да я бы предпочел в будущем проекты, которые используют стандартные и широко зарекомендованные приемы, чем велосипедыНу тогда надо ещё пообещать самому не баловаться, а использовать только «стандартные и широко зарекомендованные приемы».
а не в предметную область бизнесаboooring…
пообещать самому не баловаться,
Сейчас так и делаю, смотрю кто решал те или иные проблемы на github, развивается ли проект и т.д. и внедряю по возможности.
boooring
Ну не знаю, мне вот в бизнес интересней вникать, чем в очередную новомодную библиотеку. Точнее интереснее когда применение некоторых практик помогают эффективней решать проблемы бизнеса.
Сейчас так и делаю, смотрю кто решал те или иные проблемы на github, развивается ли проект и т.д. и внедряю по возможности.Очень часто такое приводит к эффекту «leftpad-a».
Когда в проект добавляется миллиард зависимостей из-за самых простейших вещей. Особенно с .net core это очень заметно, становится похожим на nodejs.
Сложно отслеживать зависимости, качество и безопасность этих проектов.
Недавно обсуждали с коллегами идею сделать nuget для исходников, т.е. проекты меньше определённого размера тянуть не бинарниками, а исходниками. И публиковать их в формате, чтобы можно было брать нужные части, а не «all or nothing». Т.е. ты становишься владельцем симпортированного кода и отвечаешь за него.
Ну не знаю, мне вот в бизнес интересней вникать, чем в очередную новомодную библиотеку.Все люди разные, я например повникал достаточно, чтобы бросить менеджерство и обратно разработкой заняться.
Но всё равно постоянно пытаются навесить сверху. Какое-то проклятие профессии, как будто в свой области мало сложности.
От того, что будут исходники отслеживать качество и безопасность ничуть не проще.
Кроме того любую dll можно dotPeek-ом превратить в полноценный проект C#, а потом добавить в проект как исходный код.
Но зачем ?:)
А зачем нужен атрибут TraitIgnore
? Можно же просто было делать метод в трейте абстрактным, всё равно абстрактные методы в самих трейтах не нужны (то есть, копировать их в целевой класс не надо).
Мы думали над подобным, но решили что явное объявление более правильный подход, чем подразумеваемое правило. Немного более многословный, но лично я бы предпочёл так. Хотя конечно можно обе версии добавить. т.е. игнорировать и abstract в дополнение к TraitIgnore.
Ну так не делать их приватными :) Они всё равно нужны только для того, чтобы удовлетворить компилятор/IDE, ведь пользоваться ими и так никто не будет. Зато не надо будет писать вот эти заглушки (правда, в вашем варианте можно ещё исключение просто выбрасывать):
[TraitIgnore]
private string GetNamePrefix()
{
return null;
}
Но с абстрактным методом, мне кажется, код выглядел бы чище.
Отмечу, что для множественного наследования, когда нужны только методы, вполне достаточно использовать C# 8 default interface methods.
Лично мне в C# пару раз очень пригодилась бы реализация traits как в rust, без необходимости модифицировать класс, чтобы их можно было применять к существующим типам, например из готовых библиотек.
Чтобы к классам прикреплялся интерфейс трейта, и под ним их можно было использовать как параметры в методах или обобщениях.
Можно добиться похожего поведения, если явно принимать реализацию типажа в методе:
interface ITrait<T>
{
void TraitMethod<T>(T value);
}
class External
{
}
struct ExternalTrait : ITrait<External>
{
void TraitMethod(External value) {}
}
class Consumer
{
void Consume<T, TTrait>(T value) where TTrait : struct, ITrait<T>
{
default(TTrait).TraitMethod(value);
}
}
Можно также добавить перегрузок для известных реализаций типажей (их уже легко сгенерировать автоматически):
class Extensions
{
public static void Consume(this Consumer consumer, External value)
{
consumer.Consume<External, ExternalTrait>(value);
}
}
В целом не очень красиво, т.к. на стороне потребителя нельзя просто написать value.TraitMethod()
, тем не менее у меня в одном проекте такой подход прижился.
P.S. Промазал, это ответ для SIDOVSKY
((IMyInterface)myObject).Field1
myObject.To<IMyInterface>().Field1
var stringArray = new [ "a", "b", "c"];
string.Join(", ", stringArray);
stringArray.Join(", ");
public void MyMethod(IList<int> list)
{
if (list != null && list.Count > 0)
{
// ...
}
}
public void MyMethod(IList<int> list)
{
if (list.IsNotNullOrEmpty())
{
// ...
}
}
null при сравнении всегда даёт false.
А .Count стал возвращать int? вместо из-за list?..
доселе невиданные методы появились у стандартных библиотечных классов
Посмотрит исходники или документацию.
расширения своих собственных классов
Зачем их расширять, если и так есть доступ к исходникам и можно написать по обычному, внутри самих классов? Вот с интерфейсами проблема, хотя в последней версии появилась дефолтная реализация.
Насколько я понял идею методов расширения, они используются для:
1. Добавления новых (более удобных) методов для уже закрытых для изменения классов.
2. Для массовой реализации нового поведения для заданного интерфейса. Т.е. чтобы не прописывать в каждом классе реализацию, можно сделать метод расширения на интерфейс и все классы наследники получат это поведение. Мне это напоминает реализацию интерфейса по умолчанию, которое появилось в C# 8.0.
Я с ужасом жду каждой новой фичи языка, потому что уже знаю, что первое же для чего она будет использована, это создание содома и гомморы.Ну когда что-то новое появляется, начинают экпериментировать и конечно могут от энтузиазма немного переборщить.
Экпериментировать конечно лучше на маленьких проектах, но я вполне себе допускаю что писатели из вашего примера, не считали своё изделие «содомом и гомморой» — потому что это была их «содома и гоммора», также как очень вероятно, что новый человек пришедший на ваш проект, потихоньку, за глаза рассакзывает какой-же «содом и гоммору» творит fkthat, а вы искренне гордитесь выбраному подходу, потому что это ваш «содом и гоммора».
Мда, Java, нервно
в сторонке.
SmartTraits или добавляем «множественное» наследование в C#