Rails представил некоторые базовые расширения Ruby, такие как 3.days.from_now, который возвращается, как и следовало ожидать, через три дня в будущем. С помощью методов расширения в C# теперь мы можем делать нечто подобное:
static class Extensions
{
public static TimeSpan Days(this int i)
{
return new TimeSpan(i, 0, 0, 0, 0);
}
public static DateTime FromNow(this TimeSpan ts)
{
return DateTime.Now.Add(ts);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
3.Days().FromNow()
);
}
}
Или как насчет:
static class Extensions
{
public static IEnumerable<int> To(this int from, int to)
{
return Enumerable.Range(from, to - from + 1);
}
}
class Program
{
static void Main(string[] args)
{
foreach (var i in 10.To(20))
{
Console.WriteLine(i);
}
}
}
Это в корне неверно, или бывают случаи, когда это хорошая идея, например, в таких фреймворках, как Rails?





Лично мне нравится int.To, я неоднозначно отношусь к int.Days и не люблю TimeSpan.FromNow.
Мне не нравится то, что я считаю чем-то вроде увлечения «беглыми» интерфейсами, которые позволяют писать псевдоанглийский код, но делают это путем реализации методов с именами, которые могут сбивать с толку изолированно.
Например, мне это плохо читается:
TimeSpan.FromSeconds(4).FromNow()
Понятно, что это субъективная вещь.
@Neil - метод расширения Days расширяет int для возврата TimeSpan.
Мне очень нравятся методы расширения, но я чувствую, что, когда они используются вне LINQ, они улучшают читаемость за счет ремонтопригодности.
Возьмем, к примеру, 3.Days().FromNow(). Это замечательно выразительно, и любой может прочитать этот код и сказать вам, что именно он делает. Это действительно прекрасная вещь. Как программисты, мы с радостью пишем код, который является самоописывающим и выразительным, так что он почти не требует комментариев и его приятно читать. В этом отношении этот код имеет первостепенное значение.
Однако, как кодеры, мы также несем ответственность перед потомками, и те, кто придут после нас, будут проводить большую часть своего времени, пытаясь понять, как работает этот код. Мы должны быть осторожны, чтобы не быть настолько выразительными, чтобы отладка нашего кода не потребовала прыжков среди множества методов расширения.
Методы расширения скрывают «как», чтобы лучше выразить «что». Думаю, это делает их обоюдоострым мечом, который лучше всего использовать (как и все) в умеренных количествах.
Я полагаю, что та же самая логика вернет нас обратно к сборке, но вы правы: инкапсуляция, особенно если она сделана плохо, требует затрат.
@slowplay - Суть методов расширения в том, что они нарушают инкапсуляцию.
Я на консервативной стороне спектра, по крайней мере, на данный момент, и против методов расширения. Это просто синтаксический сахар, который для меня не так важен. Я думаю, что это также может стать кошмаром для младших разработчиков, если они плохо знакомы с C#. Я бы предпочел инкапсулировать расширения в свои собственные объекты или статические методы.
Если вы собираетесь их использовать, просто, пожалуйста, не злоупотребляйте ими до такой степени, что вы делаете их удобными для себя, но возитесь с кем-либо, кто прикоснется к вашему коду. :-)
У каждого языка есть свой собственный перспектива того, каким должен быть язык. Rails и Ruby разрабатываются со своими собственными, очень разными взглядами. У PHP явно разные мнения, как и у C (++ / #) ... как и у Visual Basic (хотя, очевидно, нам не нравится их стиль).
Весы имеют множество легко читаемых встроенных функций и тщательный контроль над всем. Я бы не хотел, чтобы у вас было так много функций, которые приходилось искать каждый раз, когда вы хотите что-то сделать (и должны быть накладные расходы на производительность из-за раздутого фреймворка), но мне лично нравится Rails, потому что то, что он имеет, меня спасает. много времени на разработку.
Я предполагаю, что я говорю здесь, что если вы разрабатывали язык, займите позицию, двигайтесь оттуда и встраивайте функции, которые вы (или ваш целевой разработчик) будет использовать чаще всего.
Во-первых, интуитивное ощущение: 3.Minutes.from_now выглядит совершенно круто, но не демонстрирует, почему методы расширения хороши. Это также отражает мою общую точку зрения: круто, но я никогда особо не скучал по ним.
Вопрос: 3.Minutes - это временной интервал или угол?
Пространства имен, на которые ссылается оператор using «обычно», влияют только на типы, теперь они внезапно решают, что означает 3.Minutes.
Так что лучше всего «не дать им сбежать» .
Все общедоступные методы расширения в пространстве имен, на которое, вероятно, будут ссылаться, в конечном итоге становятся «своего рода глобальными» - со всеми потенциальными проблемами, связанными с этим. Храните их внутри сборки или помещайте в отдельное пространство имен, которое добавляется к каждому файлу отдельно.
Я согласен с Siz и худым консерватором в этом вопросе. В Rails есть такие вещи, так что на самом деле это не так запутанно. Когда вы пишете методы «days» и «fromnow», нет гарантии, что ваш код не содержит ошибок. Кроме того, вы добавляете зависимость в свой код. Если вы поместите свои методы расширения в отдельный файл, вам понадобится этот файл в каждом проекте. Вы должны включать этот проект в проект всякий раз, когда он вам нужен.
Все это говорит о том, что для действительно простых методов расширения (таких как использование Джеффом "оставил" или использование thisismatt для days.fromnow выше), которые существуют в других фреймворках / мирах, я думаю, что это нормально. Любой, кто знаком с датами, должен понимать, что означает «3.Days (). FromNow ()».
Лично я предпочитаю пока использовать их экономно и подождать, чтобы увидеть, как их используют Microsoft и другие крупные организации. Если мы начнем видеть много кода, учебных пособий и книг, использующих такой код, как 3.Days (). FromNow (), он очень часто его использует. Если им будет пользоваться лишь небольшое количество людей, то вы рискуете, что ваш код будет слишком сложно поддерживать, потому что недостаточно людей знакомо с тем, как работают расширения.
В связи с этим, мне интересно, как сравнивается производительность между обычным циклом for и циклом foreach? Казалось бы, второй метод потребует много дополнительной работы для компьютера, но я недостаточно знаком с концепцией, чтобы знать наверняка.
Татисматт не указал int.Days, скорее, он привел пример TimeSpan.Days. Не могли бы вы поправить, пожалуйста?