Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Serginio1, Вы писали:
V>>>Это всё к тому, что твой пример с copy&paste вот этого:
V>>>V>>>where(x => x > q)
V>>>
V>>>в общем случае является плохой практикой.
V>>>Но язык позволяет только такую.
S>> Чем это плохо?
V>Тем, вестимо, что в каждом конкретном месте можно допустить ошибку.
V>По сей причине и рождается "матрица специализаций", типа этой.
V>По ссылке автогенерённый код. В этом смысле С++ позволяет выполнять такую кодогенерацию прямо в исходниках.
И ты тудаже. Ты мои ссылки вообще игнорируешь? По приведенной ссылке прежде много кода генерится всего из за того, что код не инлайнится.
Я привел тебе ссылки где методы инлайнятся и нет разницы между value и ref типами
S>>В С++ зря штоли ввели Лямбды?
V>Моя рука потихоньку тянется к лицу. ))
V>Давай сделаем паузу и посмотрим на это всё повнимательней. Лямбды хороши исключительно и только для уникальных случаев, в этом и состоит их ЦЕЛЕВАЯ фишка — они же захватывают текущий контекст! Т.е., твоё x => x > q — это ж вовсе не лямбда (вот почему рука дрогнула в направлении лица), это ж у тебя просто некая "маленькая процедура", которая использует возможность локального объявления процедур (лямбд), не используя при этом их основной механизм. Вполне же можно было объявить такой предикат вне контекста использования, верно? Т.е., получилась лишь некая экономия сугубо на "оформлении" такого предиката в виде отдельной ф-ии.
А что же это такое? Лямбда, замыкание, который может захватывать и внутренние переменные например
var f=5;
.Where(x => x > q+f).Select(x => x + f).Sum();
Еще раз посмотри как эти лямбды разворачиваются
Optimising LINQ
roslyn-linq-rewrite
roslyn-linq-rewrite
This tool compiles C# code by first rewriting the syntax trees of LINQ expressions using plain procedural code, minimizing allocations and dynamic dispatch.
Example input code
public int Method1()
{
var arr = new[] { 1, 2, 3, 4 };
var q = 2;
return arr.Where(x => x > q).Select(x => x + 3).Sum();
}
Allocations: input array, array enumerator, closure for q, Where delegate, Select delegate, Where enumerator, Select enumerator.
Decompiled output code
public int Method1()
{
int[] arr = new[] { 1, 2, 3, 4 };
int q = 2;
return this.Method1_ProceduralLinq1(arr, q);
}
private int Method1_ProceduralLinq1(int[] _linqitems, int q)
{
if (_linqitems == null) throw new ArgumentNullException();
int num = 0;
for (int i = 0; i < _linqitems.Length; i++)
{
int num2 = _linqitems[i];
if (num2 > q)
num += num2 + 3;
}
return num;
}
V>Т.е., речь о том, что неуникальный случай в C# описать не так-то просто (тем паче с должной эффективностью).
S>>Нет язык позволяет использовать
S>>S>>public static IEnumerable<TSource> Where<TSource>(
S>> this IEnumerable<TSource> source,
S>> Func<TSource, bool> predicate
S>>)
S>>
S>>То есть я могу использовать любой дженерик делегат .
V>Не можешь. В теле дотнетной лямбды происходит автовывод типов, поэтому ты вызываешь методы конкретных типов. А для реализации предиката в виде генерика исходные типы должны поддерживать некие данные ЗАРАНЕЕ ограничения на шаблонах или использовать т.н. "объекты-словари операций", навроде IComparer<T>, который в свою очередь может оперировать лишь типами, над которыми ПРЕДВАРИТЕЛЬНО заданы некие ограничения в виде опять и снова интерфейсов.
И что мне мешает объявить метод?
bool MyMetod<T>(T x)
S>>Просто лямбды удобнее как для написания так и для чтения, а так же для оптимизации компиляции
V>Конечно удобны. Но я на это тоже уже отвечал заранее:
V>V>Понятно, что x => x.Y выглядит тривиально, это был лишь пример. В общем случае "оно" может быть не тривиальным, т.к. именно под нетривиальные объемы кода пишут те самые шаблоны "многоразового применения" — в этом их фишка.
V>С++ позволяет комбинировать технику шаблонов и лямбд, используя каждую из техник по прямому назначению, т.е. заставляя их выполнять исключительно "свою" часть работы.
Это же все можно делать и на C#