Interpolated strings: есть идеи, как подправить производител
От: Sinix  
Дата: 19.04.16 07:47
Оценка:
Про что речь:

в библиотеке CodeJam есть методы-ассерты с api вида
Code.AssertState(someCondition, "Message #123");
Code.AssertState(someCondition, "Message #{0}", 123);

ну, т.е. обычная перегрузка и вариант с строкой форматирования.

в 99.99% случаев ассерт не срабатывает, форматирование не требуется.


В чём проблема: рекомендации решарпера заменяют второй вариант на
Code.AssertState(someCondition, $"Message #{123}");
, компилятор превращает эту строчку в
Code.AssertState(someCondition, string.Format("Message #{0}", 123));
, получаем ~120x падение в производительности из-за того, что теперь форматирование выполняется при каждом вызове метода.

Как показывает практика, простое решение "не верьте советам решарпера" не работает
Будем искать сложное.

Матчасть:
Надо сказать, что мы тут не одиноки, на те же проблемы наткнулся, скажем, NLog.
Подписываюсь под

>We generally believe that libraries will mostly be written with different API names for methods which do different things. Therefore overload resolution differences between FormattableString and String don't matter, so string might as well win. Therefore we should stick with the simple principle that an interpolated string is a string. End of story.

Assumptions are the Base of evil.


Обсуждения этого дела в issues рослина:
https://github.com/dotnet/roslyn/issues/46
https://github.com/dotnet/roslyn/issues/10221


Предполагаемое решение (нам не подходит, т.к. к static-классу extension-метод не прикрутишь):
http://pvlerick.github.io/2016/01/poking-the-csharp-compiler-overload-resolution-for-string-and-formattablestring/

Бенчмарк:
         Formattable:   260ms, ips:          38 442 435,53 | Mem:  2 288,09 kb, GC 0/1/2: 279/0/0 => 10000000
    FormattableNoArg:   109ms, ips:          91 461 100,22 | Mem:  2 232,11 kb, GC 0/1/2: 101/0/0 => 10000000
      FormattableInt:    41ms, ips:         242 532 426,59 | Mem:    904,04 kb, GC 0/1/2: 76/0/0 => 10000000
              String:     3ms, ips:       3 317 850 033,18 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 10000000
       String.Format:   125ms, ips:          79 656 647,98 | Mem:     64,04 kb, GC 0/1/2: 178/0/0 => 10000000
       FuncNoClosure:    28ms, ips:         344 932 255,31 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 10000000
         FuncClosure:    91ms, ips:         109 542 823,03 | Mem:  1 376,06 kb, GC 0/1/2: 203/0/0 => 10000000
   FuncClosureFormat:    93ms, ips:         107 068 788,48 | Mem:  1 376,06 kb, GC 0/1/2: 203/0/0 => 10000000

Done.

  код
FormattableString как параметр не прикрутишь, таргетинг на 4.5 стоит, там этого типа нет.
        static void AssertState(bool condition, IFormattable message)
        {
            if (!condition)
                throw new InvalidOperationException(message.ToString());
        }
        static void AssertStateMessage(bool condition, string message)
        {
            if (!condition)
                throw new ArgumentException(message);
        }
        static void AssertStateMessage(bool condition, string messageFormat, params object[] args)
        {
            if (!condition)
                throw new ArgumentException(string.Format(messageFormat, args));
        }
        static void AssertStateFunc(bool condition, Func<string> messageCallback)
        {
            if (!condition)
                throw new InvalidOperationException(messageCallback());
        }


        static void Main(string[] args)
        {
            Console.WindowWidth = 120;

            const int Count = 10 * 1000 * 1000;
            Measure("Formattable", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertState(true, $"Message #{i}");
                }
                return Count;
            });
            Measure("FormattableNoArg", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertState(true, $"Message #0");
                }
                return Count;
            });
            Measure("FormattableInt", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertState(true, i);
                }
                return Count;
            });
            Measure("String", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertStateMessage(true, "Message #0");
                }
                return Count;
            });
            Measure("String.Format", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertStateMessage(true, "Message #{0}", i);
                }
                return Count;
            });
            Measure("FuncNoClosure", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertStateFunc(true, () => "Message #0");
                }
                return Count;
            });
            Measure("FuncClosure", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertStateFunc(true, () => $"Message #{i}");
                }
                return Count;
            });
            Measure("FuncClosureFormat", () =>
            {
                for (int i = 0; i < Count; i++)
                {
                    AssertStateFunc(true, () => string.Format("Message #{0}", i));
                }
                return Count;
            });

            Console.WriteLine();
            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        static void Measure(string name, Func<long> callback)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var mem = GC.GetTotalMemory(true);
            var gc00 = GC.CollectionCount(0);
            var gc01 = GC.CollectionCount(1);
            var gc02 = GC.CollectionCount(2);

            var sw = Stopwatch.StartNew();
            var result = callback();
            sw.Stop();

            var mem2 = GC.GetTotalMemory(false);
            var gc10 = GC.CollectionCount(0);
            var gc11 = GC.CollectionCount(1);
            var gc12 = GC.CollectionCount(2);

            var memDelta = (mem2 - mem) / 1024.0;
            var gcDelta0 = gc10 - gc00;
            var gcDelta1 = gc11 - gc01;
            var gcDelta2 = gc12 - gc02;

            Console.WriteLine(
                "{0,20}: {1,5}ms, ips: {2,22:N} | Mem: {3,9:N2} kb, GC 0/1/2: {4}/{5}/{6} => {7,6}",
                name, sw.ElapsedMilliseconds, result / sw.Elapsed.TotalSeconds, memDelta, gcDelta0, gcDelta1, gcDelta2, result);
        }


Собственно вопрос:
Ну и как с этим жить? В смысле, есть у кого-то опыт дизайна API, позволяющего и удовлетворить сторонников interpolated strings, и не убить при этом перфоманс приложения?

UPD Добавил пример с Func для ленивого получения строки.
Отредактировано 19.04.2016 8:41 Sinix . Предыдущая версия . Еще …
Отредактировано 19.04.2016 8:05 Sinix . Предыдущая версия .
Re: Interpolated strings: есть идеи, как подправить производительность?
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.16 07:58
Оценка: 31 (2)
Здравствуйте, Sinix, Вы писали:
S>Ну и как с этим жить? В смысле, есть у кого-то опыт дизайна API, позволяющего и удовлетворить сторонников interpolated strings, и не убить при этом перфоманс приложения?
Ну, судя по процитированному результату, придётся отказаться от static классов в пользу синглетонов, не к ночи будь помянуты:
Code.Jam.AssertState(someCondition, "Message #123"); // Jam extension method is called
Code.Jam.AssertState(someCondition, "Message #{0}", 123); // Jam instance method is called
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Interpolated strings: есть идеи, как подправить производительность?
От: Sinix  
Дата: 19.04.16 08:01
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>Ну, судя по процитированному результату, придётся отказаться от static классов в пользу синглетонов, не к ночи будь помянуты:


Это за границей добра и зла по-моему.
У библиотеки конечно неформальный девиз "да, мы упоролись", но это про планку качества кода, а не в буквальном смысле
Re: Lazy
От: Qbit86 Кипр
Дата: 19.04.16 08:24
Оценка: 28 (2)
Здравствуйте, Sinix, Вы писали:

S>Ну и как с этим жить? В смысле, есть у кого-то опыт дизайна API, позволяющего и удовлетворить сторонников interpolated strings, и не убить при этом перфоманс приложения?


Может, передавать ленивые строки? Lazy<string> или Func<string>. Они будут форситься, только если сработает ассерт.
Глаза у меня добрые, но рубашка — смирительная!
Re: Interpolated strings: есть идеи, как подправить производител
От: vmpire Россия  
Дата: 19.04.16 08:39
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Как показывает практика, простое решение "не верьте советам решарпера" не работает

Возможно, глупый вопрос: в почему это простое решение не работает?
Re[2]: Lazy
От: Sinix  
Дата: 19.04.16 08:42
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Может, передавать ленивые строки? Lazy<string> или Func<string>. Они будут форситься, только если сработает ассерт.

Не особо лучше. Добавил в стартовый пост, см на количество аллокаций.
Re[2]: Interpolated strings: есть идеи, как подправить производител
От: Sinix  
Дата: 19.04.16 08:43
Оценка:
Здравствуйте, vmpire, Вы писали:

S>>Как показывает практика, простое решение "не верьте советам решарпера" не работает

V>Возможно, глупый вопрос: в почему это простое решение не работает?

Это к остальным участникам проекта вопрос
Re[3]: Interpolated strings: есть идеи, как подправить производительность?
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.04.16 08:50
Оценка:
Здравствуйте, Sinix, Вы писали:
S>Это за границей добра и зла по-моему.
Стар стал, не вижу почему. Ну, то есть чем статик проперти хуже статик метода?

S>У библиотеки конечно неформальный девиз "да, мы упоролись", но это про планку качества кода, а не в буквальном смысле

А вот мне больше вот что интересно: на основании чего решарпер даёт такие ценные советы?
Т.е. с чего он решил, что такое преобразование семантически эквивалентно? У него есть какая-то эвристика про string, params object[] => FormattableString?
Может быть, можно подтюнить решарпер?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Interpolated strings: есть идеи, как подправить производительность?
От: Jack128  
Дата: 19.04.16 09:24
Оценка: 68 (1) +1
Здравствуйте, Sinclair, Вы писали:

S>А вот мне больше вот что интересно: на основании чего решарпер даёт такие ценные советы?

S>Т.е. с чего он решил, что такое преобразование семантически эквивалентно? У него есть какая-то эвристика про string, params object[] => FormattableString?

https://github.com/rsdn/CodeJam/blob/master/Main/src/Assertions/Code.cs#L261
StringFormatMethod("messageFormat") — говорит том, что messageFormat — это форматированая строка. А решарпер все форматные строки предлагает заменить на interpolated strings.
Re[4]: Interpolated strings: есть идеи, как подправить произ
От: Sinix  
Дата: 19.04.16 09:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>Это за границей добра и зла по-моему.

S>Стар стал, не вижу почему. Ну, то есть чем статик проперти хуже статик метода?
Проблема в том, что у нас мелкая прикладная библиотека, не свой фреймворк.
Лепить концепции по принципу как левой ноге вздумается — это верная дорога к NUnit, которого только ленивый не пинал за api в стиле
Assert.That(I, Think.There.Should.Be.Moar.Dots).


Вот есть у нас пользователь, он хочет использовать ассерты. Мы говорим, что все ассерты записываются через Code.*

Ок, пользователь набивает Code, и что ему подсунет автодополнение?
В текущем варианте — всё ок, из имён методов всё очевидно.

В варианте с синглтоном получится что-то типа Code.Assert.State(allOk, $"Some {message}!");

И так придётся оформлять _все_ ассерты. Даже те, которые не требуют строк-сообщений, например, Code.NotNull(arg, nameof(arg)).
Во-первых, потому что иначе будет путаница.
Во-вторых — иначе мы крупно попадём, когда всё-таки понадобится добавить перегрузку с строкой форматирования.

Такой бардак хорош для API, которое вызывается в единицах мест. Для ассертов, которые расставляются буквально по всему коду, это полный провал.

S>>У библиотеки конечно неформальный девиз "да, мы упоролись", но это про планку качества кода, а не в буквальном смысле

S>А вот мне больше вот что интересно: на основании чего решарпер даёт такие ценные советы?
Как мне кажется, основной довод — "нам нужно больше фич". Во всяком случае, вот этот
Автор: Sinix
Дата: 04.03.11
косяк спустя 5 лет так и не починили.
Я им периодически скидываю очередной "ребят, вы снова ломаете студию", они его вежливо закрывают с комментом из серии "don't worry, be happy" — так и живём

Вот последний, ниччего не поменялось.


S>Т.е. с чего он решил, что такое преобразование семантически эквивалентно? У него есть какая-то эвристика про string, params object[] => FormattableString?

Ну, как эвристика... JetBrains просто добавляют подсказки на каждую новую фичу шарпа, см на те же "To expression body", или "Loop can be converted into a LINQ".
UPD: Забыл написать про "помечен как StringFormatMethod", Jack128 уже про это ответил.

S>Может быть, можно подтюнить решарпер?

Угу, есть мысля попросить добавить в JetBrains.Annotations атрибут [ConditionalFormatMethod] и не предлагать interpolated string для таких методов.
Осталось найти, где об этом спросить, чтоб дошло до разработчиков, а не отфильтровалось саппортом
Отредактировано 19.04.2016 9:55 Sinix . Предыдущая версия .
Re[5]: Interpolated strings: есть идеи, как подправить произ
От: qxWork Голландия http://www.jetbrains.com/company/people/Coox_Sergey.html
Дата: 19.04.16 16:37
Оценка: 69 (1)
Здравствуйте, Sinix, Вы писали:

S>>Может быть, можно подтюнить решарпер?

S>Угу, есть мысля попросить добавить в JetBrains.Annotations атрибут [ConditionalFormatMethod] и не предлагать interpolated string для таких методов.
S>Осталось найти, где об этом спросить, чтоб дошло до разработчиков, а не отфильтровалось саппортом
Можешь считать, что уже дошло, правда, случайно
Вообще есть трекер, есть специальный форум, да и в саппорт можно писать, справились бы ))
Re[6]: Interpolated strings: есть идеи, как подправить произ
От: Sinix  
Дата: 19.04.16 16:50
Оценка:
Здравствуйте, qxWork, Вы писали:


W>Можешь считать, что уже дошло, правда, случайно

W>Вообще есть трекер, есть специальный форум, да и в саппорт можно писать, справились бы ))

О, спасиб
До форума руки не дошли, вечером честно собирался написать.
Нужно продублировать / расписать подробности? Если да — где лучше?
Re[5]: Interpolated strings: есть идеи, как подправить произ
От: Пельмешко Россия blog
Дата: 19.04.16 19:59
Оценка: 115 (5) +1 :))
Здравствуйте, Sinix, Вы писали:

S>>А вот мне больше вот что интересно: на основании чего решарпер даёт такие ценные советы?

S>Как мне кажется, основной довод — "нам нужно больше фич".

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

С интерполяцией банальная проблема — как только начинаешь ей пользоваться, то случается разрыв — половина кода в проекте $"вот {такая}", а вторая половина ("немного {0}", другая). И возникает банальное желание привести все к одному виду — к интерполяции строк. Не потому что это модно и молодежно, не потому что нам надо что-то новое показывать в редакторе чтобы выглядеть по-прежнему полезным тулом, а потому что мы реально считаем такую форму записи форматный строк предпочтительной в C# 6.0 проектах. Не смотря на то, что интерполяция не позволяет выразить всех сценариев `string.Format`а, все же вы устраняете проблему нетипизированных форматных вызовов. Вдумайтесь, на самом деле R# трансформацией в интерполяцию наоборот делает себя менее полезным!

Что касается проблемы с assert-методами: мы просто продолбали этот сценарий, который конечно здорово подкашивает веру в единообразие кода форматирования строк Мы определенно подточим инспекцию для всех методов, похожих на Assert и всякие WriteIf (думаю, эвристики по сигнатуре или наличия [AssertionMethod] будет достаточно), чтобы срабатывания там не было совсем. Я хочу заметить, что сейчас инспекция "Pass string interpolation" имеет severity HINT, который имеет самых "мягкий" рекомендативный характер и в редакторе хинты еле видно.

К сожалению, фичи для C# 6.0 дизайнятся и имплементятся в момент времени, когда в мире слишком мало C# 6.0 кода чтобы мы наступили на все грабли и учли все косяки до выката релиза. Поэтому мы вынуждены балансировать между желанием научить пользователям новым языковым идиомам и опасностью навредить пользовательскому codebase'у. Ну а дальше уже время и найденные пользователями грабли приводят систему к равновесию, как иначе?

Что касается советуемых R# трансформаций, приводящих к лишним аллокациям или деградирующим производительность — мы никогда не скрывали, что R# в первую очередь руководствуется краткостью/декларативностью/каноничностью кода, а не "производительностью". Это сделано осознанно, а не потому что мы не знаем что какие-нибудь вызовы переопределенных виртуальных методов на типах-значениях устроняет боксинг или что LINQ-методы плодят аллокации на энумераторы и замыкания. Мы можем долго спорить, должен ли обычный .NET программист экономить на каждой аллокации или он все же он знает на что идет когда пишет на языке программирования все более высокого уровня (и в случае реальных проблем возмет профайлер или статический анализатор аллокаций и почистит аллокации на горячем коде), но не думаю что это будет продуктивно.

Еще один момент который я не могу понять — почему если вас волнует "производительность", но есть желание по-прежнему пользоваться R#, то не выключить просто инспекцию и расшарить всей команде...

S>Вот последний, ниччего не поменялось.


Я понимаю ваше неудобство, но блин, придумали же специально диалоговое окно при первых нажатиях хоткеев, которые есть и в VS и R# — выбираешь который нужен и забываешь о проблемах. Без вашего ведома мы давно уже ничего не перебиваем студийное в плане хоткеев, если вы конечно не применили все R#'ные хоткеи разом

S>>Т.е. с чего он решил, что такое преобразование семантически эквивалентно? У него есть какая-то эвристика про string, params object[] => FormattableString?

S>Ну, как эвристика... JetBrains просто добавляют подсказки на каждую новую фичу шарпа, см на те же "To expression body", или "Loop can be converted into a LINQ".

Семантику конечно обычно пытаемся сохранить, но не так "сильно" как компиляторщики (помню обсуждения в розлине a la "а что если структура в .ToString() меняет культуру текущему треду?" по поводу устранения боксинга в конкатенации строк). С интерполяцией в assert-методах переборщили, конечно

Что касается инспекций о новых языковых конструкциях: вы когда-нибудь задумывались сколько программистов узнает о языковых фичах только потому что IDE им рассказало?

Я думаю вас уже не разубедить, что инспекции в решарпере работают из принципа "давай сделаем это... потому что можно!", но лишь добавлю что в инспекциях типа "to expression body" на самом деле даже пишутся эвристики чтобы попытаться понять, будет-ли пользовательский код не менее "читабелен". Например, тела-выражения не советуются когда тело содержит лямбда-выражения (чтобы не получались всякие T P => x => y) или присваивания (мы же не любим когда присваивают внутри выражений, а не отдельным statement'ом, ага?). Оценить глубину выражений и их вид после форматирования сложно, но размышляем и над этим...

S>>Может быть, можно подтюнить решарпер?

S>Угу, есть мысля попросить добавить в JetBrains.Annotations атрибут [ConditionalFormatMethod] и не предлагать interpolated string для таких методов.
S>Осталось найти, где об этом спросить, чтоб дошло до разработчиков, а не отфильтровалось саппортом

Мы вас слышим и обязательно починим этот кейс, спасибо большое что вынесли на обсуждение!
Re[6]: Interpolated strings: есть идеи, как подправить произ
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.04.16 20:21
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Я думаю вас уже не разубедить, что инспекции в решарпере работают из принципа "давай сделаем это... потому что можно!", но лишь добавлю что в инспекциях типа "to expression body" на самом деле даже пишутся эвристики чтобы попытаться понять, будет-ли пользовательский код не менее "читабелен".


Только местами они какие то довольно странные. К примеру, судя по всему, оно не предлагается, когда в выражении используется string interpolation. Почему — у меня идей нет.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[7]: Interpolated strings: есть идеи, как подправить произ
От: Пельмешко Россия blog
Дата: 19.04.16 20:53
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Пельмешко, Вы писали:


П>>Я думаю вас уже не разубедить, что инспекции в решарпере работают из принципа "давай сделаем это... потому что можно!", но лишь добавлю что в инспекциях типа "to expression body" на самом деле даже пишутся эвристики чтобы попытаться понять, будет-ли пользовательский код не менее "читабелен".


AVK>Только местами они какие то довольно странные. К примеру, судя по всему, оно не предлагается, когда в выражении используется string interpolation. Почему — у меня идей нет.


На то они и эвристики, что их сложно объяснить Приходится "безусловные" варианты трансформаций оформлять в виде отдельных выключенных инспекций (со строкой "(when possible)" в имени) для желающих.

Возможно, у вас какой-нибудь другой сквигл/хайлайтинг перебивает "to expression body", без кода сложно сказать

Re[6]: Interpolated strings: есть идеи, как подправить произ
От: Sinix  
Дата: 19.04.16 21:00
Оценка: 3 (1)
Здравствуйте, Пельмешко, Вы писали:

S>>Как мне кажется, основной довод — "нам нужно больше фич".


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


Опс, похоже я переборщил с сарказмом
Мои извинения

Если б оно было серьёзной проблемой, а не поводом поворчать за жизнь — был бы уже нормальный тикет + дубль постом в профильном форуме. По факту же проблема не в решарпере, причём даже дважды.

Во-первых, главный косяк в принятой в проекте политике "ну и что, что местами false positives, и уровень Hint? Всё равно следуем рекомендациям, т.к. проверяется автоматом". Тут я даже спорить не буду — рано или поздно или на все грабли понаступаем, или политика подзаточится под реальную жизнь. Обычный процесс, короче.

Во-вторых, затык в спорном решении C# team "перегрузка с FormattableString будет игнорироваться". Отсутствие решарпера тут скорее повредило бы — косяк вылез бы гораздо позже.

Дальше постараюсь ограничиться конструктивом.

П>а потому что мы реально считаем такую форму записи форматный строк предпочтительной в C# 6.0 проектах.

Ну вот тут у вас вечная проблема — вы заодно собираете все грабли первопроходцев, и, что самое обидное, эти грабли игнорите. Т.е. если suggestion с самого начала не учитывал сценарии, когда он больше вредит чем помогает, то так он годами и не меняется.

Я пару раз пытался этот момент донести, ещё лет 5 назад что ли, не получилось.


П>Что касается проблемы с assert-методами: мы просто продолбали этот сценарий, который конечно здорово подкашивает веру в единообразие кода форматирования строк Мы определенно подточим инспекцию для всех методов, похожих на Assert и всякие WriteIf (думаю, эвристики по сигнатуре или наличия [AssertionMethod] будет достаточно), чтобы срабатывания там не было совсем.

Я бы предложил явную разметку с [ConditionalFormatMethod] (имя атрибута условное). Потому что те же грабли были не только в ассертах, но и в логгерах, ссылку на NLog в первом посте приводил.


П>Что касается советуемых R# трансформаций, приводящих к лишним аллокациям или деградирующим производительность — мы никогда не скрывали, что R# в первую очередь руководствуется краткостью/декларативностью/каноничностью кода, а не "производительностью".

С одной стороны, это конечно прикольно. С другой, именно из-за этого минимум раз в полгода приходится чинить последствия "очередной джуниор поверил решарперу".
Вот свежачок
Автор: Sinix
Дата: 02.04.16
.

В общем это главное, что меня раздражает в решарпере. На втором месте — стремление заменять не только плохие места студии, но и хорошие. Вот зачем рослиновский rename или стандартные тултипы подменять, к примеру? Кстати, вот эти два пункта индивидуально не отключаются никак?


П>Еще один момент который я не могу понять — почему если вас волнует "производительность", но есть желание по-прежнему пользоваться R#, то не выключить просто инспекцию и расшарить всей команде...

Потому что таких "спорных" рекомендаций штук 10, если не больше, сходу не вспомню. И всплывают они бывает не сразу, а сильно постфактум. Кроме того, большинство пользователей вообще не считают нужным что-то в настройках менять. И продавить изменения когда приходишь на старый проект... в общем почти всегда оказывается дешевле периодически чинить баги. Жизнь — боль, ага


S>>Вот последний, ниччего не поменялось.

П>Я понимаю ваше неудобство, но блин, придумали же специально диалоговое окно при первых нажатиях хоткеев, которые есть и в VS и R# — выбираешь который нужен и забываешь о проблемах.
П>Без вашего ведома мы давно уже ничего не перебиваем студийное в плане хоткеев, если вы конечно не применили все R#'ные хоткеи разом

Возможно я криво сформулировал этот момент в тикете, но в этот раз идея не сработала. Чистая установка, Visual Studio Scheme — перебило.
В студии нет сочетания "просто" Ctrl-D, только составные хоткеи с ним.


П>Что касается инспекций о новых языковых конструкциях: вы когда-нибудь задумывались сколько программистов узнает о языковых фичах только потому что IDE им рассказало?

Вот этим товарищам лучше и не подсказывать:P

А то потом получается, что человек использует фичу не потому что нужно, а потому что R# советует. В последнее время предпочитаю этот момент оговаривать в соглашениях по кодированию явно — дешевле выходит, чем потом искать нечаянные закладки по всему коду
Re[5]: Interpolated strings: есть идеи, как подправить произ
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.04.16 06:16
Оценка: 69 (1) +1
Здравствуйте, Sinix, Вы писали:

S>В варианте с синглтоном получится что-то типа Code.Assert.State(allOk, $"Some {message}!");

Ну, ну, не всё так плохо:
using static CodeJam.Root; // HA-HA

public static void Main()
{
   Code.AssertState(someCondition, "Message #123"); // extension method
   Code.AssertState(someCondition, $"Message #{123}"); // instance method
}


Ну и соответственно
using System;

namespace CodeJam
{
        public static class Root
        {
                public static CodeImpl Code { get; } = new Code();
        /// <summary>
        /// State assertion
        /// </summary>
        [DebuggerHidden, MethodImpl(AggressiveInlining)]
        [AssertionMethod]
        public void AssertState(this Code code,
            bool condition,
            [NotNull] string message)
        {
            if (!condition)
                throw CodeExceptions.InvalidOperation(message);
        }
        }

    /// <summary>
    /// Assertions class.
    /// </summary>
    [PublicAPI]
    public partial class CodeImpl
    {
        /// <summary>
        /// State assertion
        /// </summary>
        [DebuggerHidden, MethodImpl(AggressiveInlining)]
        [AssertionMethod]
        public void AssertState(
            bool condition,
            [NotNull] FormattableString message)
        {
            if (!condition)
                throw CodeExceptions.InvalidOperation(message.ToString());
        }

        /// <summary>
        /// State assertion
        /// </summary>
        [DebuggerHidden, MethodImpl(AggressiveInlining)]
        [AssertionMethod, StringFormatMethod("messageFormat")]
        public void AssertState(
            bool condition,
            [NotNull] string messageFormat,
            [CanBeNull] params object[] args)
        {
            if (!condition)
                throw CodeExceptions.InvalidOperation(messageFormat, args);
        }
        #endregion
    }
}


S>И так придётся оформлять _все_ ассерты. Даже те, которые не требуют строк-сообщений, например, Code.NotNull(arg, nameof(arg)).

S>Во-первых, потому что иначе будет путаница.
S>Во-вторых — иначе мы крупно попадём, когда всё-таки понадобится добавить перегрузку с строкой форматирования.
S>Такой бардак хорош для API, которое вызывается в единицах мест. Для ассертов, которые расставляются буквально по всему коду, это полный провал.

Ну, с решарпером разобрались — тем не мнее, вопрос остаётся тем же самым — ведь interpolated strings может быть использован не только благодаря решарперу.
По-хорошему, чинить надо компилятор.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Interpolated strings: есть идеи, как подправить произ
От: Sinix  
Дата: 20.04.16 06:57
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>В варианте с синглтоном получится что-то типа Code.Assert.State(allOk, $"Some {message}!");

S>Ну, ну, не всё так плохо:
Вот этот вариант вполне может прокатить. Как минимум одно решение уже есть


S>Ну, с решарпером разобрались — тем не мнее, вопрос остаётся тем же самым — ведь interpolated strings может быть использован не только благодаря решарперу.

S>По-хорошему, чинить надо компилятор.

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

В общем, если эту идею никто больше не продавит — будем обходить
Re[7]: Interpolated strings: есть идеи, как подправить произ
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.04.16 07:28
Оценка:
Здравствуйте, Sinix, Вы писали:


S>Ага, я то же самое писал ув. Пельмешко выше.

S>Про чинить компилятор спрашивал, ответ — заведи отдельный метод и не страдай фигнёй

А можно спросить, где явная реализация explicit строки к FormattableString? Совсем отстал от жизни
и солнце б утром не вставало, когда бы не было меня
Re[8]: Interpolated strings: есть идеи, как подправить произ
От: Sinix  
Дата: 20.04.16 07:30
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>>Про чинить компилятор спрашивал, ответ — заведи отдельный метод и не страдай фигнёй


S>А можно спросить, где явная реализация explicit строки к FormattableString? Совсем отстал от жизни

Я сейчас явно торможу, т.к. вообще не понял вопрос

Можешь как-нибудь переформулировать?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.