В последнее время всё чаще строю многоэтажные конструкции типа:
xml.Div(new { @class = "editor-area" }, () => {
if (!HideBackButton()) {
xml.PTag(() => {
xml.ImageActionRef(Page.Content.ImgUrl(IMG_PREVIOUS_BUTTON), "To the List", ActionNameForBackButton(), "Back to the List", ParentListRoutes());
});
}
xml.FieldSet((fieldset) => {
fieldset.Legend(LegendText());
if (!string.IsNullOrEmpty(model.ErrorMessage)) {
xml.Div(new { @class = "error-message" }, () => {
xml.WriteString(model.ErrorMessage);
});
}
if (model.Exception != null) {
xml.Div(new { @class = "error-exception" }, () => {
xml.PrintException(model.Exception);
});
}
xml.ComplexFieldHidden(GetLambdaFroSerializedObject(m => m.SerializedOriginalModel), model.SerializedOriginalModel);
if (fields != null) {
foreach (var one_field in fields) {
one_field.Render(xml);
}
} else if (customFields != null) {
customFields(xml);
} else {
throw new InvalidOperationException("Do not have any field for render!");
}
if (! this.HideSubmitButton())
{
xml.SubmitButton("Submit");
}
});
});
помеченные жирным конструкции могут вкладываться друг в друга весьма глубоко, если не в одном методе, то в их последовательном вызове. Вовсю используются замыкания.
в данном случае, это как бы Presentation, но планирую использовать такой же подход на уровне контроллеров и вообще по жизни.
Так вопрос, чем это может грозить? Потерей производительности, например?
Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
Здравствуйте, Neco, Вы писали:
N>в данном случае, это как бы Presentation, но планирую использовать такой же подход на уровне контроллеров и вообще по жизни. N>Так вопрос, чем это может грозить? Потерей производительности, например? N>Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
Я бы беспокоился больше по поводу читабельности. А она, по-моему, в приведенном примере хромает на обе ноги.
Здравствуйте, Lloyd, Вы писали:
L>Я бы беспокоился больше по поводу читабельности. А она, по-моему, в приведенном примере хромает на обе ноги.
Хех-хех, да это есть ))
Но пока идей, как это улучшить, нет. Может у Вас есть? Буду признателен.
Здравствуйте, Neco, Вы писали:
N>Здравствуйте, Lloyd, Вы писали:
L>>Я бы беспокоился больше по поводу читабельности. А она, по-моему, в приведенном примере хромает на обе ноги. N>Хех-хех, да это есть )) N>Но пока идей, как это улучшить, нет. Может у Вас есть? Буду признателен.
Кстати, раз уж я спрашиваю про идею, то пожалуй скажу для чего такая конструкция нужна (чтобы можно было исходя из требования что-то предлагать, а не из кода). По сути нужно иметь возможность повторно использовать элементы дизайна. В моём случае это Asp.Net MVC, хотя от оригинала уже мало что осталось. Проблема зародилась в том, что при объединении нескольких mvc-контролов в один более сложный (например, кнопка с текстом — т.е. по сути гиперлинк с картинкой и текстом внутри), предлагалось либо не париться и дублировать, либо писать своё расширение, код которого в общем-то, будет состоять из бубнов с TagBuilder'ом. И сделать такой код повторно используемым я не понял как. Постепенно пришёл к тому, что всякое расширение любого html элемента, который может в себе что-то содержать, должно принимать параметр-лямбду, типа subHtml. Если сообщать вместо лямбды string, то визуально нарушается ход событий (т.е. сначала готовим начинку, а потом её используем). Таким образом такая конструкция и случилась.
Здравствуйте, MozgC, Вы писали:
MC>- Не использовать многоэтажные лямбда-конструкции?
Это логично, но они неспроста появились — т.е. они решают вполне конкретную задачу.
В общем, я Lloyd'у написал подробное объяснение.
Здравствуйте, Neco, Вы писали:
L>>Я бы беспокоился больше по поводу читабельности. А она, по-моему, в приведенном примере хромает на обе ноги. N>Хех-хех, да это есть )) N>Но пока идей, как это улучшить, нет. Может у Вас есть? Буду признателен.
Здравствуйте, Neco, Вы писали:
N>В последнее время всё чаще строю многоэтажные конструкции типа:
ИМХО, ничего страшного нет.
N> xml.Div(new { @class = "editor-area" }, () => {
N> if (!HideBackButton()) {
N> xml.PTag(() => {
// сделать разве что "поуже", не так широко,
// перенеся длинные строки на несколько строк.
N> xml.ImageActionRef(Page.Content.ImgUrl(IMG_PREVIOUS_BUTTON),
"To the List", ActionNameForBackButton(),
"Back to the List", ParentListRoutes());
N> });
N> }
// убрал бы скобки вокруг одного параметра лямбды
N> //xml.FieldSet((fieldset) => {
xml.FieldSet(fieldset => {
N> fieldset.Legend(LegendText());
N> if (!string.IsNullOrEmpty(model.ErrorMessage)) {
N> xml.Div(new { @class = "error-message" },
// А тут убрал бы не обязательные скобки.
() => xml.WriteString(model.ErrorMessage););
N> }
N> if (model.Exception != null) {
N> xml.Div(new { @class = "error-exception" },
// И тут.
() => xml.PrintException(model.Exception););
N> }
N> xml.ComplexFieldHidden(
GetLambdaFroSerializedObject(m => m.SerializedOriginalModel),
model.SerializedOriginalModel);
N> if (fields != null) {
N> foreach (var one_field in fields) {
N> one_field.Render(xml);
N> }
N> } else if (customFields != null) {
N> customFields(xml);
N> } else {
N> throw new InvalidOperationException("Do not have any field for render!");
N> }
// Этот абзац сильвы выбивается из общего стиля:
// скобки не так расставлены, "this." …
N> if (!HideSubmitButton()) {
N> xml.SubmitButton("Submit");
N> }
N> });
N> });
Так же (но это уже не совсем к читабельности, хотя может и к ней) смущает "new { @class = "editor-area" }" — набор атрибутов не на столько большой, что бы сложно было бы описать один единственный раз его и пользщоваться далее уже типизированными аналогами.
N>помеченные жирным конструкции могут вкладываться друг в друга весьма глубоко, если не в одном методе, то в их последовательном вызове. Вовсю используются замыкания. N>в данном случае, это как бы Presentation, но планирую использовать такой же подход на уровне контроллеров и вообще по жизни. N>Так вопрос, чем это может грозить? Потерей производительности, например?
Ну это вряд ли.
N>Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
Я бы не беспокоился.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Neco, Вы писали:
N>в данном случае, это как бы Presentation, но планирую использовать такой же подход на уровне контроллеров и вообще по жизни.
У лямбд есть существенный недостаток. Это неимение имени. Имя — это ясный абстрактный коментарий того, что данный код делает. Неимение имени существенно снижает читабельность а следовательно сопровождаемость кода. Поэтому для сложных конструкций, где с одного взгляда не поймешь что делегат делает, именованные функции рулят.
N>Так вопрос, чем это может грозить? Потерей производительности, например? N>Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
Не должно, ежели это не битовыжимательство.
Здравствуйте, Neco, Вы писали:
N>Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
По поводу лямбд стоит беспокоиться в Performance-critical местах, поскольку они ОЧЕНЬ небесплатны по производительности
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
N>>Слышал что-то, что бинарники бУхнут от таких конструкций (из-за количества анонимных классов), но меня это мало беспокоит. Или должно беспокоить, как считаете?
X>По поводу лямбд стоит беспокоиться в Performance-critical местах, поскольку они ОЧЕНЬ небесплатны по производительности
По сравнению с вызовом именованного метода?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
X>>По поводу лямбд стоит беспокоиться в Performance-critical местах, поскольку они ОЧЕНЬ небесплатны по производительности _FR>По сравнению с вызовом именованного метода?
Во-первых да.
Во-вторых там не только вызов, а еще
2а) Создание объекта-замыкания
2б) Создание делегата над методом класса замыкания
Все это во-первых весьма и весьма жрет ЦПУ (учитывая подводные и широко неизвестные факты в EE про создания лямбд над методом класса с дженериками)
А во-вторых объекты замыкания, если их много, весьма основательно мусорят, что приводит к mid-life crisis'у
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
X>>>По поводу лямбд стоит беспокоиться в Performance-critical местах, поскольку они ОЧЕНЬ небесплатны по производительности _FR>>По сравнению с вызовом именованного метода?
X>Во-первых да. X>Во-вторых там не только вызов, а еще X> 2а) Создание объекта-замыкания
Я так понимаю, что вряд-ли "Создание объекта-замыкания" отличается от просто создания (и инициализации) некоторого пользовательского объекта с такими же полями?
Конечно, считая относительно медленным создание любого объекта, можно придти к тому, что лямбды тормозят. Надеюсь, такие подсчёты не станут обычными для большинства прогоаммистов
Или создание именно "объекта-замыкания" обычно медленнее, чем создание пользовательского объекта?
X> 2б) Создание делегата над методом класса замыкания
Делегат тоже создаётся заметно медленнее чем обычный пользовательский объект?
X>Все это во-первых весьма и весьма жрет ЦПУ (учитывая подводные и широко неизвестные факты в EE про создания лямбд над методом класса с дженериками)
Разве EE знает, с объектом лямбды она дело имеет просто с пользовательским объектом/методом и не знает, что когда-то обыло лямбдой? Мне казалось, что "лямбда" — лишь понятия компилятора, а EE уже дела нет, что это за объект. Это не так? Другими словами, чем отличается поведение ЕЕ "про создания лямбд над методом класса с дженериками" от "про создания делегатов над методом класса с дженериками"?
X>А во-вторых объекты замыкания, если их много, весьма основательно мусорят, что приводит к mid-life crisis'у
А что можно назвать "mid-life crisis"-ом применительно к данному вопросу?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Я так понимаю, что вряд-ли "Создание объекта-замыкания" отличается от просто создания (и инициализации) некоторого пользовательского объекта с такими же полями?
правильно.
X>> 2б) Создание делегата над методом класса замыкания _FR>Делегат тоже создаётся заметно медленнее чем обычный пользовательский объект?
Да. Создание делегата — во много раз более дорогое удовольствие чем создание простого объекта
_FR>Разве EE знает, с объектом лямбды она дело имеет просто с пользовательским объектом/методом и не знает, что когда-то обыло лямбдой? Мне казалось, что "лямбда" — лишь понятия компилятора, а EE уже дела нет, что это за объект. Это не так? Другими словами, чем отличается поведение ЕЕ "про создания лямбд над методом класса с дженериками" от "про создания делегатов над методом класса с дженериками"?
Еще раз. Никаких лямбд в EE нет. Там есть только делегаты. А их создание — очень и очень дорогое удовольствие. К тому же (при определенных условиях) блокирующее, что немедленно сказывается на многопоточных приложениях
X>>А во-вторых объекты замыкания, если их много, весьма основательно мусорят, что приводит к mid-life crisis'у _FR>А что можно назвать "mid-life crisis"-ом применительно к данному вопросу?
Пользовательская логика. Ее объекты передут в Gen1 тогда как могли бы умереть в Gen0
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
X>>> 2б) Создание делегата над методом класса замыкания _FR>>Делегат тоже создаётся заметно медленнее чем обычный пользовательский объект?
X>Да. Создание делегата — во много раз более дорогое удовольствие чем создание простого объекта
ОК, это объясняет назойливое кэширование, когда это возможно, делегатов.
_FR>>Разве EE знает, с объектом лямбды она дело имеет просто с пользовательским объектом/методом и не знает, что когда-то обыло лямбдой? Мне казалось, что "лямбда" — лишь понятия компилятора, а EE уже дела нет, что это за объект. Это не так? Другими словами, чем отличается поведение ЕЕ "про создания лямбд над методом класса с дженериками" от "про создания делегатов над методом класса с дженериками"?
X>Еще раз. Никаких лямбд в EE нет. Там есть только делегаты. А их создание — очень и очень дорогое удовольствие.
ОК, я всего лишь пытался понять ваши же слова:
…(учитывая подводные и широко неизвестные факты в EE про создания лямбд над методом класса с дженериками)
X>К тому же (при определенных условиях) блокирующее, что немедленно сказывается на многопоточных приложениях
Спасибо, будет что посмотреть.
X>>>А во-вторых объекты замыкания, если их много, весьма основательно мусорят, что приводит к mid-life crisis'у _FR>>А что можно назвать "mid-life crisis"-ом применительно к данному вопросу? X>Пользовательская логика. Ее объекты передут в Gen1 тогда как могли бы умереть в Gen0
О как интересно: и термин здоровский, и не бросается так сразу в глаза.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, xvost, Вы писали:
X>>> 2б) Создание делегата над методом класса замыкания _FR>>Делегат тоже создаётся заметно медленнее чем обычный пользовательский объект?
Кстати, получается, если в примере топикстартера, например, мы заменим все лямбды на обычные, именованные методы или именованные методы во вспомагательных классах, то (поскольку и создание вспомагательных классов и создание делегатов останется) прироста производительности всё-таки не получится?
То есть, да: использование API, основанного на вызове методов через делегаты (linq/Rx и многое уже что появилось) уже чревато (из-за дороговизны создания делегата) но использование этого API посредстром анонимных методов или лямбд с точки зрения производительности всё-тки не хуже использования этого же API посредством именованных методов?
Надеюсь, не слишком завернул
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>но использование этого API посредстром анонимных методов или лямбд с точки зрения производительности всё-тки не хуже использования этого же API посредством именованных методов?
В общем, да. Разницу в микроскоп будет не заметить.
И все приведенные мною выше слова относятся действительно к performance-critical коду, который вызывается десятки тысяч раз в секунду. Там использование лямбд, linq и прочей современной радости _строго_ противопоказано.
Во всех остальных случаях, как правило, удобство чтения, восприятия и модификации кода перевешивает перфоманс-деградацию
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, _FRED_, Вы писали:
_FR>То есть, да: использование API, основанного на вызове методов через делегаты (linq/Rx и многое уже что появилось) уже чревато (из-за дороговизны создания делегата) но использование этого API посредстром анонимных методов или лямбд с точки зрения производительности всё-тки не хуже использования этого же API посредством именованных методов?
В NET альтернатива делегату, по-моему, только интерфейс, то есть выбор не особо велик, а созданный делегат, в том числе и на базе анонима, можно "кэшировать". Кстати, кто-нибудь интересовался, при использовании лямбд кэширование выполняется?