tag:blogger.com,1999:blog-8596733192274108952.post6808298747421524177..comments2024-03-12T06:00:18.305+02:00Comments on Programming stuff: Duck typing или “так ли прост старина foreach?”Sergey Teplyakovhttp://www.blogger.com/profile/14300835272589262297noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-8596733192274108952.post-34054356234460817762014-11-25T10:36:02.691+02:002014-11-25T10:36:02.691+02:00О, спасибо за ответ! Кстати, спасибо за статью)
1...О, спасибо за ответ! Кстати, спасибо за статью)<br /><br />1) Согласен. Просто из текста я понял, что упаковка должна выполняться при каждой итерации цикла, для которого создаётся итератор.<br /><br />2) Тут я пытаюсь сказать, что причина разного поведения не в том, что вызываете вы метод, который возвращает упакованный объект или метод, который возвращает структуру в стэке. - в результате и того и другого действия получатся ничем не отличающиеся объекты в стеке. Но причина в типе объявленного свойства. Другими словами, если вместо анонимного типа использовать именованный тип, то не будет иметь значение вызвали мы IEnumerable.GetEnumearator:IEnumerator или вызвали ли мы List.GetEnumerator:Enumerator<br />И соответственно я оспариваю слова "Именно по этой причине первый цикл while выведет ожидаемые 1, 2, 3, а второй цикл while …"<br /><br />Либо я неправильно что-то прочитал/понял.Eugeniy Gorbovoyhttps://www.blogger.com/profile/10403756971533461024noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-68041548187678303452014-11-24T19:24:55.730+02:002014-11-24T19:24:55.730+02:00Гонево в том, что копирование в стеке - существенн...Гонево в том, что копирование в стеке - существенно более эффективная операция, чем выделение памяти в куче, копирование в куче, а потом чистка кучи.<br /><br />В случае одного цикла - разницы не будет. Но при наличии вложенных циклов, и большого внешнего и небольшого внутреннего, мы получим аллокацию в куче на каждую внешнюю итерацию. Которых может быть 100 500. Вот тогда, разница уже будет вполне существенная.<br /><br />И соответственно: <br />> Во втором случае вы по сути объявили метод, который каждый раз возвращает новый объект в стэк.<br />Причины именно такие, как я описал. Свойство возвращает экземпляр значимого типа по значению, а значит внутреннее состояние итератора не будет меняться, когда на нем будут дергать MoveNext. А вот если при конструировании анонимного типа привести итератор к ссылочному типу, то свойство Items станет полноценно мутабельным свойством этого объекта, что позволит внешнему коду изменять его внутрненнее состояние.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-40750657276076083752014-11-24T16:30:13.939+02:002014-11-24T16:30:13.939+02:00Что-то немножко гонево:
1) "// Вызываем IEnu...Что-то немножко гонево:<br /><br />1) "// Вызываем IEnumerable GetEnumerator<br />foreach (var i in (IEnumerable)list)<br />{ } "<br />Это не афектит производительность, так как упаковка произойдёт один раз - при получении итератора.<br />И вообще всё различие будет в том, что в первом случае на одно копирование больше в стеке, во втором случае на одно копирование больше в куче. Это будет афектить производительность, но не так сильно как было бы при упаковке.<br /><br />И соответственно <br />2) "Именно по этой причине первый цикл while выведет ожидаемые 1, 2, 3, а второй цикл while … ну, проверьте сами. "<br />Причины абсолютно разные. Во втором случае вы по сути объявили метод, который каждый раз возвращает новый объект в стэк. Естественно алгоритм не работает, но это не имеет отношения в тому, к чему вы привели объект. Попробуйте сделать двойное приведение, что бы убедиться.<br /><br />п.с. Если кто-то видит в чём я не прав - прошу рассказать в чем я ошибся.Eugeniy Gorbovoyhttps://www.blogger.com/profile/10403756971533461024noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-18117154799982483352014-07-02T22:47:09.186+03:002014-07-02T22:47:09.186+03:00Класс! Спасибо! Класс! Спасибо! Alex W. Lulinhttps://www.blogger.com/profile/08400475846894229767noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-44166072183461664042012-09-12T03:23:14.410+03:002012-09-12T03:23:14.410+03:00Серёж, у тебя там опечаточка маленькая в строке гд...Серёж, у тебя там опечаточка маленькая в строке где метод интерфейса explicitly реализуется:<br /><br />IEnumerator(Of T) IEnumerator(Of T).GetEnumerator() { }<br /><br />Интерфейс должен быть IEnumerable(Of T).<br /><br />PS. А как код вставлять? Угловые кавычки режутся, не ожидал такого от блогспота..Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-44477737889483980592012-08-20T21:29:29.815+03:002012-08-20T21:29:29.815+03:00@Дмитрий: да, все правильно.@Дмитрий: да, все правильно.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-31936592297342263392012-08-20T21:21:12.677+03:002012-08-20T21:21:12.677+03:00Сергей, спасибо за ответ.
Если я всё правильно по...Сергей, спасибо за ответ.<br /><br />Если я всё правильно понял, то метод GetEnumerator() возвращает структуру, которая располагается в стеке. У анонимного типа Items - свойство типа Get/Set, т.е. мы присваиваем копию енумератора внутри экземпляра анонимного типа. В дальнейшем мы обращаемся к свойству get анонимного типа, которое внутри является методом и этот метод возвращает нам новую копию енумератора. Который, соответственно, проинициализирован "с нуля".<br /><br />Если всё правильно, то вроде уложилось в голове :)Anonymoushttps://www.blogger.com/profile/07112707334958342243noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-53099443508421751472012-08-20T21:09:01.986+03:002012-08-20T21:09:01.986+03:00В данном случае создается анонимный класс со свойс...В данном случае создается анонимный класс со свойством Items, которое возвращает каждый раз копию исходного итератора, а раз так, то MoveNext вызывается на временной копии и не изменяет настоящий итератор.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-34661425055051812312012-08-20T20:16:16.996+03:002012-08-20T20:16:16.996+03:00>> var x2 = new { Items = list.GetEnumerator...>> var x2 = new { Items = list.GetEnumerator() };<br />>> while (x2.Items.MoveNext())<br />>> {<br />>> Console.WriteLine(x2.Items.Current);<br />>> }<br /><br />Никак не могу понять, почему здесь Current всегда 0. Как будто каждый раз снова вызывается GetEnumerator(). Anonymoushttps://www.blogger.com/profile/07112707334958342243noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-50045355157409334072012-08-02T22:40:09.965+03:002012-08-02T22:40:09.965+03:00@Vladimir: ух ты! Я про ExpressionTree не знал.
Я...@Vladimir: ух ты! Я про ExpressionTree не знал.<br /><br />Я так понимаю, что с ExtensionAttribute используется тот же самый трюк, что и с атрибутом ContractArgumentValidatorAttribute, который используется в Code Contracts для превращения метода в проверку предусловия.<br /><br />@jack128: да, спасибо за ссылку.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-3940918495902891282012-08-02T11:19:00.768+03:002012-08-02T11:19:00.768+03:00вот кста http://rsdn.ru/forum/dotnet/4829209.1.asp...вот кста http://rsdn.ru/forum/dotnet/4829209.1.aspxAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-14318532363177637682012-08-02T09:06:47.349+03:002012-08-02T09:06:47.349+03:00попробую угадать:
1) конструирование ExpressionTre...попробую угадать:<br />1) конструирование ExpressionTree, компилятор не требует, чтобы тип System.Linq.Expression с фабричными методами Constant\Convert etc находился в System.Core.<br />2) System.Runtime.CompilerServices.ExtensionAttribute...<br />3) Collection initializersVladimir Matveevhttps://www.blogger.com/profile/17681155682560422821noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-20077602120192705422012-08-02T00:46:51.567+03:002012-08-02T00:46:51.567+03:00@Max: "нет, нет, все что угодно, но только не...@Max: "нет, нет, все что угодно, но только не это" (с)<br /><br />Дык, уже лет этак надцать даже Дон Бокс не может на эти COM-ы смотреть:))<br /><br />@Victor H, @Unknown: Да, по поводу исключений - все верно.<br /><br />@Unknown: ну, dynamic представляет собой утиную типизацию не на уровне компилятора, а на уровне рантайма (как вы сами об этом и заметили). я же имел ввиду другие места использования утиной типизации компилятором.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-80503398157383835922012-08-02T00:28:35.922+03:002012-08-02T00:28:35.922+03:00>> А кто сразу сможет ответить на такой вопр...>> А кто сразу сможет ответить на такой вопрос: а зачем мне нужно два метода ReadByLine и ReadByLineImpl, почему бы мне не воспользоваться лишь одним методом?<br />В вашем случае исключение будет бросаться при попытке создать итератор, а если бы вы всё впихнули в один метод, то исключение бы бросалось при попытке совершить первую итерацию. Такова природа компиляции блока итераторов<br />>> Кстати, блок foreach это далеко не единственный пример утиной типизации в языке C#, а сколько еще примеров вы можете вспомнить?<br />Кроме уже перечисленных - dynamic, но в runtimeVasiliy Novikovhttps://www.blogger.com/profile/09889006726660916877noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-70230615718684610702012-08-01T22:58:06.861+03:002012-08-01T22:58:06.861+03:00>>З.Ы. А кто сразу сможет ответить на такой ...>>З.Ы. А кто сразу сможет ответить на такой вопрос: а зачем мне нужно два метода ReadByLine и ReadByLineImpl, почему бы мне не воспользоваться лишь одним методом?<br /><br />Чтоб эксепшен был в месте вызова, а при попытке итерации?Anonymoushttps://www.blogger.com/profile/17771045604663909558noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-38489100955369378032012-08-01T22:56:58.783+03:002012-08-01T22:56:58.783+03:00>>СОМ-ы уже дали дуба
За это тебя надо лишит...>>СОМ-ы уже дали дуба<br />За это тебя надо лишить MVP )Max Paulouskyhttps://www.blogger.com/profile/00644671459767543705noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-20365035091312843182012-08-01T22:13:32.076+03:002012-08-01T22:13:32.076+03:00@jack128: да, все верно.
Я, навскидку, помню еще ...@jack128: да, все верно.<br /><br />Я, навскидку, помню еще как минимум один случай использования duck typing.Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-52341409154565959202012-08-01T22:10:16.438+03:002012-08-01T22:10:16.438+03:001) linq. Чтобы использовать query syntax примените...1) linq. Чтобы использовать query syntax применительно к т ипу MyLinqType нужно реализовать в типе(или в виде extension методов) методы Select/Where/SelectMany/Join/OrderBy ect определенной сигнатуры. Причем не обязательно реализовывать все методы, можно лишь некоторые из них.<br />И тогда можно будет писать так:<br />MyLinqType myVar = ..<br />var .. = from x in myVar where .. select ...<br /><br />2) async/await. Там, AFAIK суть таже самая. У типа MyAwaitType должен быть метод GetAwaitor() который имеет какой то там(не помню) набор методов. И тогда можно будет написать <br />MyAwaitType myAwaitVar = ...<br />await myAwaitVar;jack128https://www.blogger.com/profile/06241586079811572654noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-1887174520504368822012-08-01T21:16:18.876+03:002012-08-01T21:16:18.876+03:00@jack128: в смысле foreach и async/await? Или 2 по...@jack128: в смысле foreach и async/await? Или 2 помимо foreach?Sergey Teplyakovhttps://www.blogger.com/profile/14300835272589262297noreply@blogger.comtag:blogger.com,1999:blog-8596733192274108952.post-70558816801208727192012-08-01T21:02:03.901+03:002012-08-01T21:02:03.901+03:00>>а сколько еще примеров вы можете вспомнить...>>а сколько еще примеров вы можете вспомнить?<br />Ну лично я только два, один из которых еще не зарелизился.<br />linq и async/awaitjack128https://www.blogger.com/profile/06241586079811572654noreply@blogger.com