{"id":986,"date":"2017-01-22T20:39:31","date_gmt":"2017-01-22T19:39:31","guid":{"rendered":"http:\/\/piatkosia.k4be.pl\/wordpress\/?p=986"},"modified":"2017-01-24T21:28:23","modified_gmt":"2017-01-24T20:28:23","slug":"list-a-ienumerable","status":"publish","type":"post","link":"https:\/\/piatkosia.k4be.pl\/wordpress\/2017\/01\/22\/list-a-ienumerable\/","title":{"rendered":"List  a IEnumerable"},"content":{"rendered":"<p style=\"text-align: justify;\">DISCLAIMER:<br \/>\nArtyku\u0142 jest pisany na poziomie ameby tudzie\u017c ucznia podstaw\u00f3wki. Je\u017celi masz cho\u0107 blade poj\u0119cie na temat .net czy c# zrezygnuj z czytania tego artyku\u0142u i zajmij si\u0119 czym\u015b ciekawszym.<\/p>\n<p style=\"text-align: justify;\">Pewnego razu trafi\u0142o mi si\u0119 na facebookach takie pytanie \u201edlaczego z listy konwertuje na IEnumerable a odwrotnie nie\u201d -cytat jest skopiowany \u017cywcem, autor wola\u0142by pozosta\u0107 anonimowy. Jako \u017ce nie ma g\u0142upich pyta\u0144 i ka\u017cdy kiedy\u015b zaczyna\u0142, odpowiem koledze i innym ciekawym.<\/p>\n<p><!--more--><\/p>\n<p style=\"text-align: justify;\">Nie za bardzo wiadomo, o co chodzi z tym konwertowaniem, pewnie kolega mia\u0142 na my\u015bli rzutowanie (dla os\u00f3b lubi\u0105cych anglicyzmy: castowanie). W przypadku rzutowania nasze dane zaczynaj\u0105 by\u0107 interpretowane w nowy spos\u00f3b. Rzutowanie jest bezpieczne, je\u017celi rzutujemy z klasy pochodnej na bazow\u0105, tudzie\u017c z klasy na interfejs jaki ona implementuje, za\u015b w przypadku value type z typu w kt\u00f3rym mo\u017cemy mniej zapisa\u0107, do takiego, w kt\u00f3rym mo\u017cemy wi\u0119cej. Nale\u017cy zauwa\u017cy\u0107, \u017ce po takim zrzutowaniu nie b\u0119dziemy mieli dost\u0119pu do p\u00f3l, kt\u00f3rych ten nowy typ nie ma. No, chyba \u017ce zaczniemy wchodzi\u0107 w refleksj\u0119 i strzela\u0107 na \u015blepo czy typ pole posiada czy nie;)<\/p>\n<p style=\"text-align: justify;\">A wi\u0119c we\u017amy sobie opisan\u0105 sytuacj\u0119: mamy list\u0119 i chcemy sobie j\u0105 przypisa\u0107 (co j\u0105 oczywi\u015bcie niejawnie zrzutuje) do typu IEnumerable (bo z kolekcji niegenerycznych ju\u017c si\u0119 u\u017cywa tylko tam, gdzie trzeba zosta\u0107 we wstecznej kompatybilno\u015bci z prehistori\u0105).<\/p>\n<h2>Czym tak naprawd\u0119 jest ten IEnumerable.<\/h2>\n<p style=\"text-align: justify;\">Po pierwsze jest to interfejs (a wi\u0119c kontrakt mi\u0119dzy klasami, kt\u00f3re umawiaj\u0105 si\u0119, \u017ce dostarcz\u0105 co\u015b na pewno). Tak\u017ce nie da si\u0119 zrobi\u0107 new IEnumerable(). Jedyne co ma ten interfejs, to funkcj\u0119 GetEnumerator, kt\u00f3ra ma zwr\u00f3ci\u0107 IEnumerator, kt\u00f3ry to jedyne co ma, to informacja o aktualnym obiekcie (current), funkcj\u0119 MoveNext i funkcj\u0119 Reset. I to nie jest wiedza tajemna. To tylko F12 na typie i odczytanie metadanych:)<\/p>\n<p style=\"text-align: justify;\">A teraz po ludzku. Z czym si\u0119 kojarzy nazwa IEnumerable? No z Enumami. A enumy si\u0119 t\u0142umaczy jako typy wyliczeniowe, wi\u0119c ca\u0142y powy\u017cszy akapit mo\u017cemy om\u00f3wi\u0107 tak. Jako \u017ce typy wyliczeniowe, to oznacza, \u017ce musimy umie\u0107 po danym typie wyliczy\u0107. Po li\u015bcie si\u0119 da? Da. Po tablicy si\u0119 da? No da, bo wszystko co ma indekser da si\u0119 tak naprawd\u0119 wyliczy\u0107 bez wi\u0119kszego wysi\u0142ku. Jak w wyliczance. Jak dziecko poka\u017ce na jedno &#8222;ene&#8221;, na drugie &#8222;due&#8221; to teraz musi wiedzie\u0107, \u017ce skoro to na kt\u00f3re wskaza\u0142o \u017ce due (current) to teraz musi wskaza\u0107 na nast\u0119pne &#8222;rike&#8221; (i do tego u\u017cyje move next). Wie, na kt\u00f3re ma pokaza\u0107 (w t\u0105 sam\u0105 stron\u0119 idzie). No i musi (z tym musi to r\u00f3\u017cnie bywa) umie\u0107 wyliczy\u0107 od pocz\u0105tku.<\/p>\n<p>Lista ten &#8222;kontrakt&#8221; podpisa\u0142a. Sk\u0105d o tym wiemy? Znowu F12 i jest:<\/p>\n<pre class=\"brush: csharp;  collapse: false\">\r\npublic class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable\r\n<\/pre>\n<p>A skoro tak, mo\u017cemy bezpiecznie zrobi\u0107 taki myk.<\/p>\n<pre class=\"brush: csharp; collapse: true\">\r\n static void Main(string[] args)\r\n        {\r\n            List<int> listObject = new List<int>();\r\n            listObject.Add(5);\r\n            listObject.Add(3);\r\n            IEnumerable<int> enumerateObject = listObject;\r\n            foreach (var item in enumerateObject)\r\n            {\r\n                Console.WriteLine(item);\r\n            }\r\n            Console.ReadKey();\r\n        }\r\n<\/pre>\n<p style=\"text-align: justify;\">Dlaczego? Bo do u\u017cycia funkcji foreach jedyne czego potrzebujemy, to w\u0142a\u015bnie wiedzie\u0107 kt\u00f3ry element jest teraz i kt\u00f3ry ma by\u0107 nast\u0119pny. Gdzie sko\u0144czy\u0107? To te\u017c wiemy, bo funkcja moveNext zwraca true, je\u015bli mamy nast\u0119pny element (moveNext powinien do current przypisa\u0107 nowy element i zwr\u00f3ci\u0107 true, lub zwr\u00f3ci\u0107 false, je\u015bli elementy si\u0119 sko\u0144czy\u0142y). A co je\u015bli kto\u015b dopisze p\u00f3\u017aniej? Funkcja ma wr\u00f3ci\u0107 i doko\u0144czy\u0107 foreacha z nowymi elementami? A no jak si\u0119 kolekcja zmieni\u0142a (nie wa\u017cne jak), to dostajemy System.InvalidOperationException i na tym zabawa si\u0119 ko\u0144czy. <\/p>\n<p style=\"text-align: justify;\">I tu mamy jedyn\u0105 przewag\u0119 wolniejszego foreacha nad nieco szybszym forem. For wymaga jednak odwo\u0142ania si\u0119 po indeksie, tutaj mo\u017cemy nie wiedzie\u0107 ile element\u00f3w ma nasza kolekcja, mo\u017ce ich mie\u0107 nawet niesko\u0144czenie wiele (mo\u017cemy na przyk\u0142ad w \u015brodku doda\u0107 jak\u0105\u015b zmienn\u0105 co si\u0119 b\u0119dzie inkrementowa\u0107 i przerwa\u0107 foreacha jak przekroczy zadan\u0105 warto\u015b\u0107, by nie pobiera\u0107 w niesko\u0144czono\u015b\u0107). Mo\u017ce ich te\u017c nie mie\u0107 wcale (wtedy wejdzie do foreacha tylko po to by z niego wyj\u015b\u0107).<\/p>\n<p>Tak\u017ce ten interfejs \u015bwietnie si\u0119 nadaje do iterowania po obiektach, b\u0119d\u0105cych kolekcjami innych obiekt\u00f3w. <\/p>\n<p style=\"text-align: justify;\">Czyli robi to co lista? No niekoniecznie. Tu trza elementy po kolei ogl\u0105da\u0107 (kolejno\u015b\u0107 zale\u017cy w\u0142a\u015bnie od moveNexta). W powy\u017cszej funkcji zrobimy<\/p>\n<pre class=\"brush: csharp;   collapse: false\">\r\nConsole.WriteLine(listObject[1]);\r\n<\/pre>\n<p>Ale kompilator zaprotestuje, je\u017celi zobaczy <\/p>\n<pre class=\"brush: csharp;   collapse: false\">Console.WriteLine(enumerateObject[1]);<\/pre>\n<p style=\"text-align: justify;\">Ju\u017c VS nam to podkre\u015bli z komunikatem podobnym do tego: <\/p>\n<pre>\"CS0021  C# Cannot apply indexing with [] to an expression of type\".<\/pre>\n<p>Mimo, \u017ce sam obiekt indekser posiada, nie dostaniemy si\u0119 do niego tak \u0142atwo. Oczywi\u015bcie, z poziomu kodu mo\u017cna i zrzutowa\u0107 w 2 stron\u0119 i si\u0119 dobra\u0107 do tego elementu. Wy\u015bwietlmy \u00f3w pierwszy element na ekran: <\/p>\n<pre class=\"brush: csharp;   collapse: false\">Console.WriteLine(((List < int > )(enumerateObject))[1]);<\/pre>\n<p>W tym kawa\u0142ku kodu jednak dobieramy si\u0119 do elementu z indeksem 1 listy, a nie obiektu typu IEnumerable.<\/p>\n<p style=\"text-align: justify;\">A teraz wyobra\u017a sobie, \u017ce kto\u015b do tej zmiennej przypisze inny typ, kt\u00f3ry r\u00f3wnie\u017c podpisa\u0142 umow\u0119 IEnumerable<int>, przy czym na co\u015b, co nie ma indeksera i nie da si\u0119 zrzutowa\u0107 do opisanego typu. I co? I znowu invalid cast exception:P<\/p>\n<h2>Dlaczego jednak niejawna konwersja nie jest mo\u017cliwa?<\/h2>\n<p style=\"text-align: justify;\">Poniewa\u017c nigdy nie wiemy obiekt jakiego typu kryje si\u0119 pod zmienn\u0105 typu interfejsowego. Oczywi\u015bcie mo\u017cemy sprawdzi\u0107 to u\u017cywaj\u0105c sk\u0142adni <\/p>\n<pre>enumerateObject.GetType();<\/pre>\n<p> i dobra\u0107 si\u0119 do danych przy u\u017cyciu refleksji, jednak je\u015bli mamy wi\u0119kszy projekt i spr\u00f3bujemy gdzie\u015b u\u017cy\u0107 przypadkiem, mo\u017cemy natrafi\u0107 na InvalidCastException. Aby si\u0119 przed tym uchroni\u0107, programi\u015bci rzutuj\u0105 r\u0119cznie dopiero po sprawdzeniu typu, korzystaj\u0105c z takiej konstrukcji<\/p>\n<pre class=\"brush: csharp; collapse: false\">\r\nif (enumerateObject is List<int>)\r\n            {\r\n                secondList = enumerateObject as List<int>;\r\n            }\r\n<\/pre>\n<h2> Podsumowuj\u0105c&#8230;<\/h2>\n<p style=\"text-align: justify;\">Nawi\u0105zuj\u0105c do pytania z g\u00f3ry. Zamiana listy na IEnumerable zawsze ma sens. Dlaczego? Poniewa\u017c List zawsze mo\u017cna potraktowa\u0107 jako &#8222;daj\u0105cy si\u0119 wyliczy\u0107&#8221;, tudzie\u017c umiej\u0105cy w wyliczanki. Dlaczego w drug\u0105 stron\u0119 nie bardzo? Poniewa\u017c lista ma to co IEnumerable i jeszcze wi\u0119cej. Tym jeszcze wi\u0119cej jest chocia\u017cby mo\u017cliwo\u015b\u0107 dobrania si\u0119 do dowolnego elementu po jego indeksie, wyszukiwanie elementu na par\u0119 sposob\u00f3w, dodawanie czy usuwanie element\u00f3w (IEnumerable pozwala tylko taki element pobra\u0107, jeden po drugim). W por\u00f3wnaniu do listy IEnumerable jest&#8230; g\u0142upi.<\/p>\n<p style=\"text-align: justify;\">Acz czasami w\u0142a\u015bnie og\u0142upienie ma sw\u00f3j cel. Je\u017celi w funkcji nie chcemy robi\u0107 nic poza przej\u015bciem po kolekcji i jej obejrzeniem, warto w\u0142a\u015bnie wrzuci\u0107 j\u0105 jako \u00f3w enumerator- b\u0119dziemy pewni, \u017ce bez rzutowania nie uda nam si\u0119 na przyk\u0142ad doda\u0107 element\u00f3w z innej listy, czy j\u0105 przypadkowo wyczy\u015bci\u0107 (- przecie\u017c nie ma ani add czy addRange, ani remove ani clear).<\/p>\n<p>Jak kto\u015b chce sobie poeksperymentowa\u0107, to za\u0142\u0105czam jeszcze pliczek z kodem do zabawy. Mo\u017cna go pobra\u0107 <a href=\"http:\/\/piatkosia.k4be.pl\/playground.cs\" target=\"_blank\">st\u0105d<\/a>. My\u015bl\u0119, \u017ce ca\u0142o\u015b\u0107 pozwoli nowym zrozumie\u0107 problem.<\/p>\n<p>Generalnie jak macie jaki\u015b ciekawy problem do rozkmin, to pode\u015blijcie, ch\u0119tnie odp\u0142yn\u0119 w tym kierunku;).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>DISCLAIMER: Artyku\u0142 jest pisany na poziomie ameby tudzie\u017c ucznia podstaw\u00f3wki. Je\u017celi masz cho\u0107 blade poj\u0119cie na temat .net czy c# zrezygnuj z czytania tego artyku\u0142u<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/piatkosia.k4be.pl\/wordpress\/2017\/01\/22\/list-a-ienumerable\/\">Lecim dalej<span class=\"screen-reader-text\">List  a IEnumerable<\/span> <i class=\"fas fa-angle-right\"><\/i><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,83,103,168,49],"tags":[262,260,261],"class_list":["post-986","post","type-post","status-publish","format-standard","hentry","category-bez-kategorii","category-c_sharp","category-dzialanie","category-edu","category-programowanie","tag-c_sharp","tag-dla_poczatkujacych","tag-learning","entry"],"_links":{"self":[{"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/posts\/986","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/comments?post=986"}],"version-history":[{"count":9,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/posts\/986\/revisions"}],"predecessor-version":[{"id":1000,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/posts\/986\/revisions\/1000"}],"wp:attachment":[{"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/media?parent=986"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/categories?post=986"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/piatkosia.k4be.pl\/wordpress\/wp-json\/wp\/v2\/tags?post=986"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}