{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/csharp-historia-8-0","result":{"data":{"markdownRemark":{"html":"<p>To jest kontynuacja przeglądu historii wersji C# (<a href=\"/blog/csharp-historia-9-0\">tu znajdziesz poprzedni artykuł</a>).</p>\n<h2>Readonly members</h2>\n<p>Metoda w strukturze może być oznaczona jako <code class=\"language-text\">readonly</code> - w ten sposób oznaczamy ją jako \"instance-agnostic\", czyli po pierwsze nie może ona zmieniać stanu struktury, a po drugie - każde odwołanie do elementów struktury (tylko odczyt), będzie skutkować ostrzeżeniem.</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">WeatherMeasurement</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">double</span></span> Temperature <span class=\"token punctuation\">{</span><span class=\"token keyword\">get</span><span class=\"token punctuation\">;</span> init<span class=\"token punctuation\">;</span><span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">override</span> <span class=\"token keyword\">readonly</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">string</span></span> <span class=\"token function\">ToString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token interpolation-string\"><span class=\"token string\">$\"Temperature was </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token expression language-csharp\">Temperature</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">.\"</span></span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TU BĘDZIE WARNING</span>\n\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">readonly</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">void</span></span> <span class=\"token function\">ChangeTemperature</span><span class=\"token punctuation\">(</span><span class=\"token class-name\"><span class=\"token keyword\">double</span></span> newTemperature<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> Temperature <span class=\"token operator\">=</span> newTemperature<span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TU BĘDZIE BŁĄD KOMPILACJI</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Trzeba zapamiętać, że w przypadku \"ostrzeżeniowym\" kompilator pod spodem robi taki \"myk\": tworzy kopię struktury i na tej kopii wywołuje tę metodę/właściwość. W ten sposób oryginalna instancja nie jest dotykana, ale to dodaje ukryty narzut.</p>\n<p>P.S. Tego <code class=\"language-text\">readonly</code> nie można użyć dla metod klasy - tam działa tylko na polach.</p>\n<h2>Domyślne implementacje w interfejsach</h2>\n<p>Dotychczas interfejsy mogły mieć tylko same sygnatury metod/właściwości. Jeśli mieliśmy wiele implementacji interfejsu, ale jakiś wspólny kod, to trzeba było wprowadzać pomiędzy te implementacje a interfejs abstrakcyjną klasę \"superbazową\" i tam umieszczać tę wspólną logikę. Natomiast od C# 8.0 można to zrobić od razu w interfejsie, bez sztucznej pośredniej klasy bazowej. Na przykład:</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token keyword\">interface</span> <span class=\"token class-name\">IOrder</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token return-type class-name\"><span class=\"token keyword\">decimal</span></span> NetTotal <span class=\"token punctuation\">{</span><span class=\"token keyword\">get</span><span class=\"token punctuation\">;</span><span class=\"token punctuation\">}</span>\n    <span class=\"token return-type class-name\"><span class=\"token keyword\">decimal</span></span> VatPercentage <span class=\"token punctuation\">{</span><span class=\"token keyword\">get</span><span class=\"token punctuation\">;</span><span class=\"token punctuation\">}</span>\n    <span class=\"token return-type class-name\"><span class=\"token keyword\">decimal</span></span> GrossTotal <span class=\"token operator\">=></span> NetTotal <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">+</span> VatPercentage<span class=\"token operator\">/</span><span class=\"token number\">100</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">Order</span> <span class=\"token punctuation\">:</span> <span class=\"token type-list\"><span class=\"token class-name\">IOrder</span></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">decimal</span></span> NetTotal <span class=\"token punctuation\">{</span><span class=\"token keyword\">get</span><span class=\"token punctuation\">;</span>init<span class=\"token punctuation\">;</span><span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">decimal</span></span> VatPercentage <span class=\"token punctuation\">{</span><span class=\"token keyword\">get</span><span class=\"token punctuation\">;</span>init<span class=\"token punctuation\">;</span><span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>W tej sytuacji możemy korzystać z właściwości <code class=\"language-text\">IOrder.GrossTotal</code>, mimo że w klasie <code class=\"language-text\">Order</code> nie została ona zainicjalizowana. Ważne jest jednak to, że dostęp do niej mamy tylko, kiedy instancja klasy <code class=\"language-text\">Order</code> jest użyta w kontekście <code class=\"language-text\">IOrder</code> - inaczej nie będziemy mieli do niej dostępu. Porównaj:</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token class-name\">IOrder</span> order1 <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">Order</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span> NetTotal <span class=\"token operator\">=</span> <span class=\"token number\">100</span><span class=\"token punctuation\">,</span> VatPercentage <span class=\"token operator\">=</span> <span class=\"token number\">22</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\nConsole<span class=\"token punctuation\">.</span><span class=\"token function\">WriteLine</span><span class=\"token punctuation\">(</span>order1<span class=\"token punctuation\">.</span>GrossTotal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TU DZIAŁA</span>\n\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> order2 <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">Order</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span> NetTotal <span class=\"token operator\">=</span> <span class=\"token number\">100</span><span class=\"token punctuation\">,</span> VatPercentage <span class=\"token operator\">=</span> <span class=\"token number\">22</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\nConsole<span class=\"token punctuation\">.</span><span class=\"token function\">WriteLine</span><span class=\"token punctuation\">(</span>order2<span class=\"token punctuation\">.</span>GrossTotal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TO SIĘ NIE SKOMPILUJE</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>W drugim użyciu <code class=\"language-text\">var</code> jes tylko <em>syntactic sugar</em> - zmienna <code class=\"language-text\">order2</code> jest typu <code class=\"language-text\">Order</code>.</p>\n<h2>Pattern matching w switchach</h2>\n<p><em>Pattern matching</em> w połączeniu ze <code class=\"language-text\">switch</code> umożliwia bardzo zgrabny zapis:</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">string</span></span> <span class=\"token function\">GetFuelString</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">EngineType</span> engineType<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> engineType <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">{</span>\n    EngineType<span class=\"token punctuation\">.</span>Diesel <span class=\"token operator\">=></span> <span class=\"token string\">\"ON\"</span><span class=\"token punctuation\">,</span>\n    EngineType<span class=\"token punctuation\">.</span>Petroleum <span class=\"token operator\">=></span> <span class=\"token string\">\"95\"</span><span class=\"token punctuation\">,</span>\n    EngineType<span class=\"token punctuation\">.</span>LPG <span class=\"token operator\">=></span> <span class=\"token string\">\"LPG\"</span><span class=\"token punctuation\">,</span>\n    _ <span class=\"token operator\">=></span> <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">ArgumentOutOfRangeException</span><span class=\"token punctuation\">(</span><span class=\"token named-parameter punctuation\">message</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Unrecognized engine type\"</span><span class=\"token punctuation\">,</span> <span class=\"token named-parameter punctuation\">paramName</span><span class=\"token punctuation\">:</span> <span class=\"token keyword\">nameof</span><span class=\"token punctuation\">(</span>engineType<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Co więcej, można też \"matchować\" za pomocą warunków określonych na właściwościach, np.:</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">bool</span></span> <span class=\"token function\">HasDiscount</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Customer</span> customer<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> customer <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token punctuation\">{</span>IsVIP<span class=\"token punctuation\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">=></span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>Age<span class=\"token punctuation\">:</span> <span class=\"token operator\">&lt;</span><span class=\"token number\">18</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">=></span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>Age<span class=\"token punctuation\">:</span> <span class=\"token operator\">></span><span class=\"token number\">65</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">=></span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>FirstName<span class=\"token punctuation\">:</span> <span class=\"token string\">\"Adam\"</span><span class=\"token punctuation\">,</span> <span class=\"token named-parameter punctuation\">LastName</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Małysz\"</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">=></span> <span class=\"token return-type class-name\">true</span>\n    _ <span class=\"token operator\">=></span> <span class=\"token boolean\">false</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>W mocy pozostaje jednak ograniczenie switcha: porównywana wartość musi być stałą.</p>\n<h2>IAsyncEnumerable</h2>\n<p>O tym <a href=\"/blog/iasyncenumerable-to-jest-dobre\">isałem w oddzielnym wpisie</a>, więc odsyłam po szczegóły do niego.</p>\n<h2>Using bez klamerek</h2>\n<p>Mniej wcięć dzięki temu, że <code class=\"language-text\">using</code> może być \"inline'owy\" - kompilator sam \"ogarnie\", że \"scope\" sięga do końca \"aktualnego scope'u\".</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token keyword\">public</span> <span class=\"token return-type class-name\"><span class=\"token keyword\">bool</span></span> <span class=\"token function\">WriteToFile</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">using</span> <span class=\"token class-name\"><span class=\"token keyword\">var</span></span> stream <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token constructor-invocation class-name\">StreamWriter</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"file.txt\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// &lt;-- TU JESTEŚMY \"WEWNĄTRZ\" USINGA</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<h2>Operacje na indeksach</h2>\n<p>C# 8.0 zapewnia nam zgrabniejszy dostęp do fragmentów tablic i konkretnych pozycji, np.:</p>\n<div class=\"gatsby-highlight\" data-language=\"csharp\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-csharp line-numbers\"><code class=\"language-csharp\"><span class=\"token class-name\"><span class=\"token keyword\">var</span></span> weekdays <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"Monday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Tuesday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Wednesday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Thursday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Friday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Saturday\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Sunday\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> sunday <span class=\"token operator\">=</span> weekdays<span class=\"token punctuation\">[</span><span class=\"token operator\">^</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> weekend1 <span class=\"token operator\">=</span> weekdays<span class=\"token punctuation\">[</span><span class=\"token number\">5</span><span class=\"token range operator\">..</span><span class=\"token number\">7</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TO SAMO CO weekend2</span>\n<span class=\"token class-name\"><span class=\"token keyword\">var</span></span> weekend2 <span class=\"token operator\">=</span> weekdays<span class=\"token punctuation\">[</span><span class=\"token operator\">^</span><span class=\"token number\">2</span><span class=\"token range operator\">..</span><span class=\"token operator\">^</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// &lt;-- TO SAMO CO weekend1</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Fajne, tylko czasem może być kłopotliwe - jak tutaj przy zmiennej <code class=\"language-text\">weekend1</code>: nie dość, że na dzień dobry jest <em>mindfuck</em>, bo piątek to 4, to jeszcze drugi koniec takiego przedziału nie wchodzi do niego (dlatego jest indeks 7, którego nie ma w tablicy), czyli przedział jest jednostronnie domknięty; ale z drugiej strony jak odliczamy indeksy od końca (przykład z <code class=\"language-text\">weekend2</code>), to zasada jest odwrotna.</p>","excerpt":"To jest kontynuacja przeglądu historii wersji C# (tu znajdziesz poprzedni artykuł). Readonly members Metoda w strukturze może być oznaczona jako  - w ten sposób…","frontmatter":{"date":"20 July, 2021","path":"/blog/csharp-historia-8-0","title":"C# - historia (C# 8.0)"},"fields":{"readingTime":{"text":"4 min read"}}}},"pageContext":{}},"staticQueryHashes":["3649515864","63159454"]}