[C# 3.0] синтаксис лямбда выражений
А то это напоминает Паскаль-стильЭто напоминает запись лямбда-выражений , которая от Черча пошла.
Если больше одной переменной?
Если больше одной переменной?нет проблем
.Where(=>@c.ZipCode == 91822 && @dealer.Name == "test")
и чем твоя запись лучше? имхо, она сосёт. Особенно в случае нескольких переменных, когда неизвестен порядок аргументов. А то, как это сделано в питоне (func(arg1 = val1, arg2=val2, ... не подходит под C-стиль
собачка уже зарезервирована для других целей
бугага!
и чем твоя запись лучше? имхо, она сосёттем что ты "определяешь" переменные по требованию.
Чисто визуальное в первом варианте "с" употребляется два раза, в моем один. Число символов совпало, но это из-за того что используется односимвольная переменная, что в реальности редкость.
читай дальше, только что добавил
да, че та про порядок переменных я забыл Тогда вопрос снимается...
но это из-за того что используется односимвольная переменная, что в реальности редкостьТолько если у тебя лямбда выражения на две страницы текста каждое. А многобуквенные имена в однострочнках - дурной стиль.
однобуквенные имена, в любом случае, дурной стиль
имхо, так намного лучше бы смотрелось
var locals =
customers
.Where(customer => customer.ZipCode == 91822)
.Select(customer => new { FullName = customer.FirstName + “ “ + customer.LastName,
HomeAddress = customer.Address });
for (int i=0;i<10;++i) customers[i].blabla;
Неужели customer_index, customerId или еще как-нибудь позаковыристее ?
для этого foreach есть
Никогда не называл переменные x и y ?да..., с таким стилем надо поосторожнее, у нас одного чувака уволили, из-за того что он вот так переменные называл. Конечно, его уволили не только из-за этого, и иногда такие обозначения все таки используются, но это особенные случаи.
другое дело что если он один могли-бы завести дефолтовое имя типа it как в groovy (или откуда они это слизали? из руби?)
ну аргументы определять всё-равно надо если их >1тип аргументов теперь выводится, остается только порядок определять. Фактически назначаются имена номерам мест аргументов, и это делается при каждом использовании, что немного раздражает.
Матрицы приходилось перемножать ? Неужели номер строки и столбца называешь как-то длиннее чем i, j или x, y ?
Допустим, нужно умножить каждый элемент массива на 2: lambda x: x*2 или lambda item_price: item_price * 2 ?
Матрицы приходилось перемножать ?в матрице x,y - нормально, если матрица однородная
i,j - хуже, т.к. у каждого разработчика свои предпочтения, i - по вертикали, или j - по вертикали
> Допустим, нужно умножить каждый элемент массива на 2: lambda x: x*2 или lambda item_price: item_price * 2 ?
каждый элемент массива чем является? так и называть.
т.к. у каждого разработчика свои предпочтения, i - по вертикали, или j - по вертикалиВсегда думал, что i, j при перемножении матриц выбирают как в математике.
фразы про математику хороши, пока народ параллельно, и работает, и в институте учится.
а лет через 10 после института уже хрен вспомнишь где там была i, а где j.
а лет через 10 после института уже хрен вспомнишь где там была i, а где jЕсли человек забыл, где там i, а где j, то он уж точно не помнит, как перемножать матрицы. Поэтому он посмотрит где-нибудь математический алгоритм, в котором они будут на правильном месте.
Совсем необязательно
Всегда думал, что i, j при перемножении матриц выбирают как в математикеесли матрицы именно математические, то ты прав
если же матрицы не математические, то возможны варианты
если же матрицы не математические, то возможны вариантыНу если не математические, то большинство сначала запишет i, потом j; выбрав сначала строку, а затем столбец...
каждый элемент массива чем является? так и называть.map(lambda item_price: item_price * 2, item_prices)
или
map(lambda x: x*2, item_prices) ?
Второй вариант мне кажется ничуть не менее понятным, а в первом от item_price в глазах рябит.
map(lambda price: price * 2, prices)
и хорошо видно, что на что умножается
ps
что полезного в item_ я не понял
map (*2) prices
...
map (*2) pricesа как тогда записывается?
map (price: price^2 + price) prices
map (\price=>price^2+price) prices
для этого foreach естьиногда в теле цикла бывает нужен номер
А кстати, foreach для массивов до сих пор медленнее исполняется, чем for?
иногда в теле цикла бывает нужен номервот это уже действительно плохой стиль проганья! в перечесляемом объекте должны быть все его свойства!
иногда в теле цикла бывает нужен номерциклы не нужны
string[] names = new string[] {"Вася", "Петя", "Маша", "Путин", "John Dow"};
System.Array.Sort(names);
for(int i=0; i<names.Length; ++i)
writer.WriteLine("{0}. {1}", i, names[i]);
как такой же результат получить без счётчика?
там где "не нужны" циклы, их роль играет рекурсия
names.sort
for i, name in enumerate(names):
print "%d. %s" % (i, name)
Я вот тут вижу "распечатать строки, при этом, указав перед каждой строкой номер вывеенной строки". Если ч0, это делается как-то так:
$iNameNum = 1;
foreach($names as $name) {
printf('%d. %s', $iNameNum, $name);
$iNameNum++;
}
UPD: А лучше - как-то так:
class StringsIterator {
private $arrStrings;
public function __construct(array $arrStrings) {
$this->arrStrings = $arrStrings;
}
private $iStringNum;
private function printString($string) {
printf('%d. %s', $this->iStringNum, $string);
$this->iStringNum++;
}
public function printAll {
$this->iStringNum = 1;
array_map(/*$this->printString($_1)*/array($this, "printString" $this->arrStrings);
}
}
C# 3.0 это не скомпилирует
это её личные проблемы =)
Я вот тут вижу "распечатать строки, при этом, указав перед каждой строкой номер вывеенной строки". Если ч0, это делается как-то так:Правильно, так оно тоже делается, но тут мы параллельно с foreach всё равно заводим счётчик (iNameNum). Для структур типа списков, у которых нет прямого доступа к элементам, только так и получится. А для массивов это - извращение
Просто ты тут завязываешься на то, что индекс - это действительно то, что тебе нужно. А ключи, на самом деле, могут быть какими угодно.
вы бы ещё HTML в пример привели с его <ul><li>
<ul>
<foreach $strings as $string>
<li><=$string></li>
</foreach>
</ul>
Тоже правильный вариант, и никакой завязки на индексы.
Твой вариант на C# выглядел бы так:
int i=0;
foreach(string name in names)
{
writer.WriteLine("{0}. {1}", i, name);
++i;
}
внутрях реализовывалось бы это как-то так:
int i=0;
for(IEnumerator<string> en = names.GetEnumerator; en.MoveNext; ++i)
writer.WriteLine("{0}. {1}", i, en.Current);
в общем, сомневаюсь, что читабельность или производительность от этого выше будет.
то есть, тут уже проблема не в стиле программирования, а в заказчике. Ему надо так и сказать: "Чувак, нафига тебе отчёты в txt? Давай мы тебе HTML замутим, а то придётся счётчики для циклов заводить..."
ну это ещё можно решить специальным writer`ом, что даже логично, раз нумерация является не свойством объектов а состоянием вывода.
внутрях реализовывалось бы это как-то так:Ну, если бы оптимизатор постарался.
в общем, сомневаюсь, что читабельность или производительность от этого выше будетЧитабельность - однозначно будет лучше, потому что надо писать не так, как что-то там внутри реализуется, а так, чтобы оно представляло собой именно то, что подразумевается.
Хочется вывести строки из массива, и расставить номера выведенных строк - так и делаем, заводим счётчик выведенных строк, выводим строку со значением счётчика.
Современные оптимизаторы достаточно хороши для того, чтобы писать то, что надо, а не то, как оно реально будет работать.
Воистину, мы не ищем лёгких путей
Воистину, мы не ищем лёгких путейЛёгких - для чего?
Лёгких - для написания и понимания, что тут делает вот эта строчка?
Или для облегчения работы оптимизатора, чтобы подсунуть ему уже готовую реализацию, чтобы он там никакие сложные foreach-и не распутывал, или, не дай боже, с объектами начинал работать?
Читабельность - однозначно будет лучшеОднозначно ли? Я вот не уверен. Может попросим модераторов голосовалку замутить?
В моём случае, всё очевидно - что имели в виду, то и написали.
А в твоём - хуйня какая-то выходит.
Лёгких - для написания и понимания, что тут делает вот эта строчка?Для написания - гораздо проще взять любой из for/foreach, чем париться со специализированным writer'ом, отлавливающим конец строки, который может быть и не понадобится-то больше никогда
Ну, я так понял, у тебя эта хуйня не в одном месте используется?
А в твоём - хуйня какая-то выходит.дожили... простейший сишный for-цикл у программистов уже трудности вызывает
Ты ещё скажи "простейший ассемблерный набор инструкций уже вызывает трудности, дожили".
public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource, int> action)
{
int i = 0;
foreach (var item in source)
{
action(item, i++);
}
}
names.ForEachname, index) => ...);
Тут как ни крути, а счётчик всё равно будет. Пусть даже в виде параметра у рекурсивной функции.
это кто сказал?
в C# 2.0 foreach часто выполняется для массивов быстрее, чем for, т.к. jit-у проще понять где можно выкинуть проверки на корректность индекса.
внутрях реализовывалось бы это как-то так:неправда, для массива внутрях будет так:
int i=0;
for(int j = 0; j < names.Length; ++j)
{
writer.WriteLine("{0}. {1}", i, names[j]);
++i;
}
Это называется без for.
Неправда, или ключи массива - это обязательно все целые числа от 0 до n?
для ассоциативного массива (Dictionary) - так уже не будет
это кто сказал?да уж не помню кто сказал, читал где-то. Возможно, в 1.1 так и было.
в C# 2.0 foreach часто выполняется для массивов быстрее, чем for, т.к. jit-у проще понять где можно выкинуть проверки на корректность индекса.
Сейчас посмотрел что c# 3.0 генерит, действительно, в случае с foreach заводится два параллельных счётчика. в остальном код одинаковый, элемент из массива достаётся одним и тем же ldelem.ref, то есть JIT-у что одно, что другое - всё равно, если умный, то второй счётчик должен выкинуть
string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var shortDigits = digits.Wheredigit, index) => digit.Length < index);
Console.WriteLine("Short digits:");
foreach (var d in shortDigits)
Console.WriteLine("The word {0} is shorter than its value.", d);
Взято отсюда
C# 3.0 это не скомпилируетЭто серьёзно её личные проблемы.
Теоретически можно написать что-нибудь вроде
public class IndexedEnumerator<T> : IEnumerable<KeyValuePair<int, T>>
{
private IEnumerable<T> inner;
public IndexedEnumerator(IEnumerable<T> inner)
{
this.inner = inner;
}
public IEnumerator<KeyValuePair<int, T>> GetEnumerator
{
IEnumerator<T> e = inner.GetEnumerator;
for (int i = 0; e.MoveNext; i++)
{
yield return new KeyValuePair<int, T>(i, e.Current);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator
{
return GetEnumerator;
}
[STAThread]
public static void Main(string[] args)
{
string[] zzz = { "a", "b", "c" };
foreach (KeyValuePair<int, string> kvp in new IndexedEnumerator<string>(zzz
{
MessageBox.Show("ItemId = " + kvp.Key + " Item = " + kvp.Value);
}
}
}
(с поправкой на возможность писать "var" вместо "KeyValuePair<int, string>" в третьем шарпе).
И даже, наверное, работать будет не намного медленней. Но это, блин, реальная проблема шарпа, что такого класса нет в стандартной библиотеке. Даже если закрыть глаза на то, что туплы (ака кортежи) и групповое присвоение в общем-то полезны на уровне языка.
Я даже расширю утверждение и заявлю, что это проблема всех ориентированных на программистов продуктов микрософта.
У питона правильный подход, "batteries included".
У жавы плохой, но терпимый подход, "ебитесь сами", в результате образуется несколько (но не много!) конкурирующих в-некотором-смысле-стандартных библиотек, в каждой из которых всё есть, но совокуплять их тяжело и вообще.
У микрософта отвратительный подход, "не нужно отбирать у программистов работу", вроде бы как есть _почти_ всё, но нет кучи мелочей (некоторые из которых весьма фундаментальны, вот как эта в результате программисты либо тратят жизнь на написание "for (int i = 0; i < zzz.Count; i++)", либо каждый пишет свою личную кривую, глючную и тормозную VasyaPupkin.Utils, которую тянет за всеми своими прогами.
Это очень, очень плохо и грустно!
static class EnumerateExtension
{
public static IEnumerable<KeyValuePair<int, T>> Enumerate<T>(this IEnumerable<T> sequence)
{
int i = 0;
foreach (T value in sequence)
{
yield return new KeyValuePair<int, T>(i, value);
++i;
}
}
}
class Program
{
static void Main
{
string[] names = new string[] { "Вася", "Петя", "Маша", "Путин", "John Dow" };
foreach (var x in names.Enumerate
Console.WriteLine("{0}. {1}", x.Key, x.Value);
}
}
P.S. туплы (анонимные типы) же появились в 3.0
Анонимный тип метод вернуть не может - придется object возвращать, а в вызывающем коде к пропертям через Reflection лазить.
Бесполезная штука, короче.
а в вызывающем коде к пропертям через Reflection лазить.к слову: например ASP.NET датабайндинг именно через рефлекшен вызывает свойства (WPF вроде тоже). Причем никого это как бы не замечает, везде только пишут вот какая удобная штука датабайндинг... . Вот нашел сообщение в блоге
http://www.dotnetjunkies.com/WebLog/joshuagough/archive/2006...
Там что-то про ASP 3.0, но аспнет уже вышел, ничего такого я там не увидел, все по старому Eval/Bind.
<asp:LinqDataSource
ContextTypeName="AdventureWorksDataContext"
TableName="Products"
Where="ListPrice > @SelectedPrice"
Select="new(Name, Size, StandardCost, ListPrice, DaysToManufacture)"
ID="LinqDataSource1"
runat="server">
<WhereParameters>
<asp:ControlParameter
Name="SelectedPrice"
DefaultValue="0"
ControlID="DropDownList1"
Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Products"
GroupBy="new(ProductCategory,Color)"
Select="new(Key,
Average(ListPrice) as AverageListPrice,
Count as RecordCount)"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
А вы говорите рефлекшен....
static class EnumerateExtension
{
public delegate void Proc<T>(int key, T value);
public static void Enumerate<T>(this IEnumerable<T> sequence, Proc<T> proc)
{
int i = 0;
foreach (T value in sequence)
proc(i++, value);
}
}
class Program
{
static void Main
{
string[] names = new string[] { "Вася", "Петя", "Маша", "Путин", "John Dow" };
names.Enumeratekey, value) => Console.WriteLine("{0}. {1}", key, value;
}
}
names.Enumeratekey, value) => Console.WriteLine("{0}. {1}", key, value;хуже, потому что отличается от стандартного foreach: например, break, continue, return уже не вставишь в тело цикла.
В Linq-выражениях тоже нет ни break, ни continue... Максимум что можно - интервал вырезать
что именно тебе не нравится/возмущает?
А вот кстати такой вопрос... Есть ли способ сериализовать Expression<>, пусть даже с некоторыми ограничениями?
что именно тебе не нравится/возмущает?LINQ создавали чтобы иметь строгую типизацию. А то можно просто писать сиквел стайтменты и получать DataTable-ы, причем родной сиквел для выбранной СУБД это даже круче, поскольку ты можешь использовать особенность конкретной СУБД напрямую.
Используя запросы LINQ в маркапе, убивает всю строгую типизацию, проверку на этапе компиляции и т.д.
А вот кстати такой вопрос... Есть ли способ сериализовать Expression<>, пусть даже с некоторыми ограничениями?где-то читал, что в текущей реализации сериализовать нельзя, и за это их ругали
Похоже, придётся вручную делать.
реально нужно...о замыкании надо не забывать, наверное поэтому в общем случае и не получается сериализовать... А вводить ограничение видимо тонкий момент, поэтому и не сделали...
Похоже, придётся вручную делать.
так замыкания можно вычислить на момент сериализации и сохранить в качестве значения, меня бы такой вариант устроил.
Но все-таки постоянно заниматься таким "разворотом мозга" напряжно, да и значения иногда хочется вернуть так, чтобы получатель строго типизированно мог с ними работать, а класс новый описывать лень.
Кстати, вопрос. Может ли анонимный класс реализовывать интерфейс. Это было бы очень кстати.
Не понимаю, почему нельзя было хотя бы сделать так:
public interface IMyClass
{
new { int, string } GetValue; // Так описывать анонимные классы в интерфейсе
}
public class MyClass : IMyClass
{
public var GetValue // Реализация метода из интерфейса
{
return new { Num = 4, Str = "Four" };
}
public var GetAnotherValue // Компилятор может определить тип возвращаемого выражения
{
return new { Num = 5, Str = "Five" };
}
public new { int, string } GetYetAnotherValue // Зададим тип явно
{
return new { Num = 6, Str = "Six" };
}
}
При этом считать, что два анонимных класса имеют одинаковый тип, если у них одинаковые свойства (типы, имена, порядок).
Появиться-то они появились, только от них толку как от козла молока.
Анонимный тип метод вернуть не может - придется object возвращать, а в вызывающем коде к пропертям через Reflection лазить.
Они вот эти и предлагают пользоваться, подписываясь на событие LinqDatasource.Selecting
http://weblogs.asp.net/scottgu/archive/2007/09/07/linq-to-sq...
Правда, сверху в этой же статье есть замечание
Note: you do not need to write your query expression in-line within the event handler. A cleaner approach would be to encapsulate it within a helper method that you just call from the event handler. I show how to create one of these helper methods in the beginning of my Part 8 blog post (using a GetProductsByCategory helper method).
Короче, MS в своем стиле .
И такое пишет General Manager within the Microsoft Developer Division, афигеть ....
Интересно в ReSharper-e сделают герелку — из анонимного класса генерировать и подставить именованный класс?
Еще интересно, когда они его выпустят?..
получаете анонимный класс,
List<int> lMass = new int[] { 1, 2, 3 }.ToList<int>
var @var =
from m in lMass
where m > 1
select new {m, sm = m.ToString m5 = -m};
а потом делаете с ним что хотитие
var @varlist = @var.ToList;
@varlist.Sorta1, a2) => a1.m5.CompareTo(a2.m5;
var @vardic = @var.ToDictionary(a => a.m);
@vardic.Add(1, new { m = 1, sm = "", m5 = 1 });
foreach (var varelem in @var)
{
...
}
или конвертируете в нужную структуру данных и возвращаете
return new KeyValuePair<int, string>(@var.First.m, @var.First.sm);
return @var.ToDictionary(a => a.m, a => a.sm);
return @var.ToLookup(a => a.m, a => a.sm);
вроде оч удобная штука!
Ведь и VS уже давно вышел, а про беты я уж и не говорю.
Хотя бы выпускали патчи для 2005-го решейпера, чтобы он мог работать с 2008-м...
или конвертируете в нужную структуру данных и возвращаетенужная структура это IEnumerable<?> , где ? — название анонимного класса
Хотя бы выпускали патчи для 2005-го решейпера, чтобы он мог работать с 2008-м...не, там движок сильно переделывать надо
ну если тебе нужен такой класс - напиши. в чем проблема?
ну если тебе нужен такой класс - напиши. в чем проблема?класс и так уже есть, у него просто нет имени. А имя тоже особо не нужно, оно требуется только, чтобы передать из метода наружу коллекцию.
А проблема в том, что это сложнее мейтайнить, например, авто-промерти ввели по той же причине — меньше кода проще майнтейнить.
Оставить комментарий
6yrop
раз уж упрощали синтаксис, зачем аргументы делегата в начале определять? Сделали бы какую-нибудь плюшечку, чтобы помечать аргумент при первом использовании. А то это напоминает Паскаль-стиль — определяем локальные переменные в начали метода и только тогда их можно использовать