<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>xlab &#187; .net</title>
	<atom:link href="http://xlab.pl/tag/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://xlab.pl</link>
	<description>XSolve laboratory - dzielimy się tym co wiemy...</description>
	<lastBuildDate>Mon, 09 Jan 2012 15:29:06 +0000</lastBuildDate>
	<language>pl</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>.NET i memory leak?! czyli dzień z życia programisty</title>
		<link>http://xlab.pl/net-i-memory-leak-czyli-dzien-z-zycia-programisty/</link>
		<comments>http://xlab.pl/net-i-memory-leak-czyli-dzien-z-zycia-programisty/#comments</comments>
		<pubDate>Fri, 01 Apr 2011 10:53:37 +0000</pubDate>
		<dc:creator>Jarek Kożdoń</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[Memory leak]]></category>
		<category><![CDATA[Profiler]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[XAML]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=1796</guid>
		<description><![CDATA[Dzisiaj historia z życia wzięta – czyli ponad dzień pracy programisty. Akcja będzie wartka, a potencjalnemu czytelnikowi zalecam wczytanie do pamięci RAM wewnątrz głów dll&#8217;ek z zasobami o WPF&#8217;ie. Zaczęło się niewinnie, przyszło zgłoszenie od testerów, że aplikacja zajmuje strasznie dużo pamięci, a przy wykonywaniu pewnej operacji ta zajętość jeszcze rośnie i wielce nazywać to [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #000000">Dzisiaj historia z życia wzięta – czyli ponad dzień pracy programisty. Akcja będzie wartka, a potencjalnemu czytelnikowi zalecam wczytanie do pamięci RAM wewnątrz głów dll&#8217;ek z zasobami o WPF&#8217;ie.</span></p>
<p><span style="color: #000000">Zaczęło się niewinnie, przyszło zgłoszenie od testerów, że aplikacja zajmuje strasznie dużo pamięci, a przy wykonywaniu pewnej operacji ta zajętość jeszcze rośnie i wielce nazywać to chcieli memory leakiem. Jako programista raczej nie dowierzałem, przecież w dot-necie tak być nie może, zgodnie z teorią pamięć sama się zwalnia, Pan Garbage Collector robi wszystko za nas&#8230; pomijając fakt że programista generalnie nie wierzy testerom, którzy zawsze szukają dziury w całym&#8230;</span></p>
<p><span style="color: #000000">ot&#8230; teoretycznie&#8230;</span></p>
<p><strong><span style="color: #000000">Godzina 1</span></strong></p>
<p><span style="color: #000000">kawa i te sprawy&#8230; partyjka piłkarzyków, przecież zadanie na pewno zostanie odbite!</span></p>
<p><strong><span style="color: #000000">Godzina 2</span></strong></p>
<p><span style="color: #000000">Sprawdzam – i już widzę, że jednak coś jest na rzeczy. Coś się nie zwalnia. Dziwne&#8230;</span></p>
<p><strong><span style="color: #000000">Godzina 3</span></strong></p>
<p><span style="color: #000000">No tak – testerzy jak to w ich zwyczaju coś znaleźli, ale sami nie wiedzieli co. Nie trzeba nawet wykonywać zgłoszonej akcji&#8230; wystarczy wejść do okienka i wyjść z niego. I tak kilka razy i task manager poda nam jakieś fantastyczne, zawrotne sumy pożeranej przez naszą aplikację pamięci.</span></p>
<p><strong><span style="color: #000000">Godzina 4</span></strong></p>
<p><span style="color: #000000">Kod przeanalizowany, wszystko co trzeba zdaje się być zwalniane. Wszystko gra, a jednak&#8230; jednak nie&#8230; Powoli pojawiają się jednak promyki nadziei na znalezienie przyczyny.</span></p>
<p><strong><span style="color: #000000">Godzina 5</span></strong></p>
<p><span style="color: #000000">Nadzieja rośnie, podejrzany jest namierzony – udało się zablokować przeciek. Ale coś jednak tutaj nie pasuje, coś jest nie-tak. Bug niby zwalczony, ale wewnątrz płonie ogień buntu, że przecież to nie była faktyczna przyczyna. Trzeba sięgnąć po cięższą artylerię. Trzeba skombinować jakiegoś profilera z opcją analizy pamięci. Na pierwszy ogień idzie <strong>ANTS Memory Profiler</strong> firmy <strong>Red Gate</strong> („tej od .<strong>NET Reflectora</strong>”). Piłkarzyki, kawa&#8230; w końcu musi się pobrać i zainstalować (tak trochę tej kawy dzisiaj&#8230; to piątek, zmęczenie tygodnia się kumuluje, a rano wstałem o 5:15&#8230; pobiegać&#8230;)</span></p>
<p><strong><span style="color: #000000">Godzina 6</span></strong></p>
<p><span style="color: #000000">Profiler odpalony, bardzo pozytywne zaskoczenie, intuicyjność pierwsza klasa, bez czytania tutoriali, bez instrukcji w ciągu kilku minut znajduję – prawdziwą przyczynę błędu. Otóż okienko WPF zostaje w pamięci, a jest trzymane przez&#8230; przez jego własną kontrolkę! Przecież to niemożliwe&#8230; przecież „<strong>GC</strong>” wykrywa i cykliczne referencje i w ogóle te wszystkie szmery bajery&#8230;</span></p>
<p><span style="color: #000000">Mija jeszcze kilka chwil zanim ogarnę cały temat&#8230;</span></p>
<p><span style="color: #000000">Sprawdzam co to za kontrolka, Google, dokumentacja MSDN i robi mi się smutno, dopisuję 1 (słownie jedną) linię kodu i „fixuję buga w JIRA&#8217;ze”.</span></p>
<p><span style="color: #000000">Po przydługim wstępie wytłumaczenie na przykładzie, dla uproszczenia malutka aplikacja WPF – 2 formatki i jedna klasa oczywiście:</span></p>
<h3><span style="color: #000000">Okienko główne z buttonem i akcją otwierającą nowe okienko:</span></h3>
<p><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">Window</span></span><span style="color: #ff0000"><span style="font-size: small"> x</span></span><span style="color: #0000ff"><span style="font-size: small">:</span></span><span style="color: #ff0000"><span style="font-size: small">Class</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;MemoryLeaking.Window1&#8243;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">xmlns</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">xmlns</span></span><span style="color: #0000ff"><span style="font-size: small">:</span></span><span style="color: #ff0000"><span style="font-size: small">x</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">Title</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;Window1&#8243;</span></span><span style="color: #ff0000"><span style="font-size: small"> Height</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;170&#8243;</span></span><span style="color: #ff0000"><span style="font-size: small"> Width</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;306&#8243;&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">Grid</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">Button</span></span><span style="color: #ff0000"><span style="font-size: small"> Margin</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;50,50,50,50&#8243;</span></span><span style="color: #ff0000"><span style="font-size: small"> Click</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;Button_Click&#8221;&gt;</span></span><span style="color: #a31515"><span style="font-size: small">Take the RAM!</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">Button</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">Grid</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">Window</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;</span></span></p>
<p><span style="color: #0000ff"><span style="font-size: small">namespace</span></span><span style="color: #000000"><span style="font-size: small"> <span style="color: #000000">MemoryLeaking</span><br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> </span></span><span style="color: #808080"><span style="font-size: small">&lt;summary&gt;<br />
</span></span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> Interaction logic for Window1.xaml<br />
</span></span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> </span></span><span style="color: #808080"><span style="font-size: small">&lt;/summary&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">public</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #0000ff"><span style="font-size: small">partial</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #0000ff"><span style="font-size: small">class</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">Window1</span></span><span style="color: #000000"><span style="font-size: small"> : </span></span><span style="color: #2b91af"><span style="font-size: small">Window<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">public</span></span><span style="color: #000000"><span style="font-size: small"> <span style="color: #000000">Window1()<br />
</span></span></span><span style="color: #000000"><span style="font-size: small">{<br />
</span><span style="font-size: small">InitializeComponent();<br />
</span></span><span style="font-size: small"><span style="color: #000000">}<br />
</span> </span><span style="color: #0000ff"><span style="font-size: small"><br />
private</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #0000ff"><span style="font-size: small">void</span></span><span style="color: #000000"><span style="font-size: small"> <span style="color: #000000">Button_Click</span>(</span></span><span style="color: #0000ff"><span style="font-size: small">object</span></span><span style="color: #000000"><span style="font-size: small"> sender, </span></span><span style="color: #2b91af"><span style="font-size: small">RoutedEventArgs</span></span><span style="color: #000000"><span style="font-size: small"> e)<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">new</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">MemoryTakingWindow</span></span><span style="color: #000000"><span style="font-size: small">().ShowDialog();<br />
</span></span><span style="color: #2b91af"><span style="font-size: small">GC</span></span><span style="color: #000000"><span style="font-size: small">.Collect();<br />
</span></span><span style="color: #000000"><span style="font-size: small">}<br />
</span><span style="font-size: small">}<br />
</span><span style="font-size: small">}</span></span></p>
<h3><span style="color: #000000">Klasa „zjadająca RAM” (banalnie prosta – lista stringów, do każdego przypisujemy GUID):</span></h3>
<p><span style="color: #0000ff"><span style="font-size: small">namespace</span></span><span style="color: #000000"><span style="font-size: small"> MemoryLeaking<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">class</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">MemoryTakingClass<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">private</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">List</span></span><span style="color: #000000"><span style="font-size: small">&lt;</span></span><span style="color: #0000ff"><span style="font-size: small">string</span></span><span style="color: #000000"><span style="font-size: small">&gt; MemoryTaker;<br />
</span></span><span style="font-size: small"><br />
</span><span style="color: #0000ff"><span style="font-size: small">public</span></span><span style="color: #000000"><span style="font-size: small"> MemoryTakingClass()<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #000000"><span style="font-size: small">MemoryTaker = </span></span><span style="color: #0000ff"><span style="font-size: small">new</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">List</span></span><span style="color: #000000"><span style="font-size: small">&lt;</span></span><span style="color: #0000ff"><span style="font-size: small">string</span></span><span style="color: #000000"><span style="font-size: small">&gt;(100000);<br />
</span></span><span style="color: #0000ff"><span style="font-size: small"><br />
for</span></span><span style="color: #000000"><span style="font-size: small"> (</span></span><span style="color: #0000ff"><span style="font-size: small">int</span></span><span style="color: #000000"><span style="font-size: small"> i = 0; i &lt; 100000; i++)<br />
</span></span><span style="font-size: small"><span style="color: #000000">{</span><br />
</span><span style="color: #000000"><span style="font-size: small">MemoryTaker.Add(</span></span><span style="color: #2b91af"><span style="font-size: small">Guid</span></span><span style="color: #000000"><span style="font-size: small">.NewGuid().ToString());<br />
</span></span><span style="color: #000000"><span style="font-size: small">}<br />
</span><span style="font-size: small">}<br />
</span><span style="font-size: small">}<br />
</span><span style="font-size: small">}</span></span></p>
<h3><span style="color: #000000">Okienko „zjadające RAM”:</span></h3>
<p><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">Window</span></span><span style="color: #ff0000"><span style="font-size: small"> x</span></span><span style="color: #0000ff"><span style="font-size: small">:</span></span><span style="color: #ff0000"><span style="font-size: small">Class</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;MemoryLeaking.MemoryTakingWindow&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">xmlns</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">xmlns</span></span><span style="color: #0000ff"><span style="font-size: small">:</span></span><span style="color: #ff0000"><span style="font-size: small">x</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">xmlns</span></span><span style="color: #0000ff"><span style="font-size: small">:</span></span><span style="color: #ff0000"><span style="font-size: small">winForms</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms&#8221;<br />
</span></span><span style="color: #ff0000"><span style="font-size: small">Title</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;MemoryTakingWindow&#8221;</span></span><span style="color: #ff0000"><span style="font-size: small"> Height</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;134&#8243;</span></span><span style="color: #ff0000"><span style="font-size: small"> Width</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;306&#8243;&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">Grid</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;</span></span><span style="color: #a31515"><span style="font-size: small">WindowsFormsHost</span></span><span style="color: #ff0000"><span style="font-size: small"> Name</span></span><span style="color: #0000ff"><span style="font-size: small">=&#8221;host&#8221;&gt;&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">WindowsFormsHost</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">Grid</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">&lt;/</span></span><span style="color: #a31515"><span style="font-size: small">Window</span></span><span style="color: #0000ff"><span style="font-size: small">&gt;<br />
</span></span><span style="font-size: small"><span style="color: #0000ff"><br />
namespace</span> MemoryLeaking<br />
</span><span style="font-size: small">{<br />
</span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> </span></span><span style="color: #808080"><span style="font-size: small">&lt;summary&gt;<br />
</span></span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> Interaction logic for MemoryTakingWindow.xaml<br />
</span></span><span style="color: #808080"><span style="font-size: small">///</span></span><span style="color: #008000"><span style="font-size: small"> </span></span><span style="color: #808080"><span style="font-size: small">&lt;/summary&gt;<br />
</span></span><span style="color: #0000ff"><span style="font-size: small">public</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #0000ff"><span style="font-size: small">partial</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #0000ff"><span style="font-size: small">class</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">MemoryTakingWindow</span></span><span style="color: #000000"><span style="font-size: small"> : </span></span><span style="color: #2b91af"><span style="font-size: small">Window<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">public</span></span><span style="color: #000000"><span style="font-size: small"> MemoryTakingWindow()<br />
</span></span><span style="font-size: small">{<span style="color: #000000"><br />
</span></span><span style="font-size: small"><span style="color: #000000">InitializeComponent();</span></span></p>
<p><span style="color: #0000ff"><span style="font-size: small">this</span></span><span style="color: #000000"><span style="font-size: small">.DataContext = </span></span><span style="color: #0000ff"><span style="font-size: small">new</span></span><span style="color: #000000"><span style="font-size: small"> </span></span><span style="color: #2b91af"><span style="font-size: small">MemoryTakingClass</span></span><span style="color: #000000"><span style="font-size: small">();<br />
</span></span><span style="color: #000000"><span style="font-size: small">}<br />
</span><span style="font-size: small">}<br />
</span><span style="font-size: small">}</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Wszystkich estetów wyczulonych na <strong>GC.Collect()</strong> proszę o wybaczenie. Użycie tego wywołania w naszym przykładzie ma bardzo głęboki sens – chodzi o to, by mieć pewność, że w pamięci zajmowanej przez proces będą zajęte wyłącznie bajty rzeczywiście zajęte. Zresztą czasem takie wywołanie <strong>ma </strong>głębszy sens, chociaż oczywiście lepiej go unikać i projektować aplikację tak, by nie było ono potrzebne. To jednak temat na osobne dyskusje.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Dla wyjaśnienia – oprócz przekopiowania powyższego kodu do własnej aplikacji należy jeszcze dodać do projektu referencję do biblioteki <strong>WindowsFormsIntegration</strong> (z niej pochodzi ta dziwna kontrolka <strong>&lt;WindowsFormsHost&gt;</strong>. Kontrolka służy do hostowania kontrolek pochodzących z tradycyjnych “winformsów” w kontrolkach / oknach <strong>WPF</strong>.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">I teraz – do dzieła. Najpierw wykres zużycia pamięci dla takiej aplikacji, po kilku wywołaniach okna <em>MemoryTakingWindow</em>:</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><a href="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_11.png"><img class="aligncenter size-full wp-image-1800" src="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_11.png" alt="" width="378" height="158" /></a><br />
</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Gdybyśmy byli budowniczymi moglibyśmy się cieszyć z (prawie) równych schodów, jednak jako programiści wpadamy właśnie w konsternację&#8230; przecież to niemożliwe, żeby takie cyrki działy w aplikacji <strong>.NET</strong>!</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Dokładnie to samo czułem. Pierwsza myśl skierowała mnie na <em>DataContext </em>(tutaj oczywiście uproszczony), gdyż w rzeczywistej aplikacji klasa do niego podpinana zabierała najwięcej pamięci i przechowywała olbrzymie ilości danych. Dokonałem małej modyfikacji w celu weryfikacji podejrzeń – mianowicie do klasy DataContext dodałem finalizer (u nas byłby to <em>~MemoryTakingClass(){ }</em>) i postawiłem tam breakpointa. Breakpoint po kilku minutach miał wciąż tyle trafień, co nasz reprezentacja w ostatnim meczu z Litwą (dla mniej zorientowanych – <strong>0</strong>).</span></span></p>
<p lang="zxx"><span style="font-size: small"><span style="color: #000000">Pierwsza myśl była banalnie prosta, skoro tam gdzieś jakieś zależności się trzymają, to przecież wystarczy odpiąć DataContext od kontrolki! Czyli dodać taki kod:</span></span></p>
<p><span style="font-size: small"><span style="color: #000000"> Closed += ((sender, e) =&gt;<br />
</span></span><span style="font-size: small"><span style="color: #000000">{<br />
</span> </span><span style="color: #0000ff"><span style="font-size: small">this</span></span><span style="color: #000000"><span style="font-size: small">.DataContext = </span></span><span style="color: #0000ff"><span style="font-size: small">null</span></span><span style="color: #000000"><span style="font-size: small">;<br />
</span></span><span style="font-size: small"><span style="color: #000000">});</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">na przykład gdzieś w konstruktorze naszego okienka MemoryTakingWindow. Postęp jest natychmiastowy – po powtórzeniu doświadczenia otrzymujemy dużo ładniejszy wynik w postaci ząbków:</span></span></span></p>
<p lang="zxx"><a href="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_2.png"><img class="aligncenter size-full wp-image-1799" src="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_2.png" alt="" width="385" height="162" /></a></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Pięknieje także liczba trafień w breakpointa – staje się dokładnie równa liczbie wywołań okna.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Na tym etapie można by zamknąć zadanie i przejść dalej. Jednak bardziej dociekliwym jednostkom jest wciąż mało i wciąż coś nie gra. Dlaczego przecież wcześniej obiekt klasy <em>MemoryTakingClass </em>nie był zwalniany? Dlaczego ciągle coś go trzymało, fakt uwolnienia go po odpięciu od DataContext jest podejrzany – oznacza przecież, że&#8230; coś ciągle trzyma okienko! Tylko co i dlaczego, no i czy na pewno.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Tutaj właśnie sięgnąłem po grubą altyrerię w postaci <strong>ANTS Memory Profilera</strong>. Po uruchomieniu aplikacji w Profilerze wykonujemy “doświadczenie” (otwarcie kilkukrotne okienka) i używamy funkcji “<strong>Take memory snapshot</strong>”, po czym w szukamy naszych klas na liście:</span></span></p>
<p lang="zxx"><a href="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_3.png"><img class="aligncenter size-full wp-image-1801" src="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_3.png" alt="" width="854" height="285" /></a></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Tutaj wybieramy naszego “podejrzanego” i wykorzystujemy opcję “<strong>Instance list</strong>”, która zwraca nam listę wszystkich instancji klasy istniejących w momencie stworzenia snapshota.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><a href="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_41.png"><img class="aligncenter size-full wp-image-1816" src="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_41.png" alt="" width="900" height="244" /></a><br />
</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">I cóż to?! W pamięci zalega nam 5 obiektów okna! Wiemy już gdzie leży przyczyna całej tej udręki – a odpinanie DataContext nie było fixem, a tylko ograniczeniem uciążliwości błędu &#8211; pozbywamy się z pamięci najcięższych obiektów, ale niestety nie wszystkich. Pozostaje ostatni krok – odpowiedź na pytanie &#8211; co powstrzymuje nasze okno przed zwolnieniem? Musimy prześledzić wszelkie referencje do niego. Gdyby przyszło nam w tym momencie analizować kod&#8230;</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Całe szczęście możemy wykorzystać ostatnią “prezentowaną” dziś opcję <strong>ANTS Profilera </strong>– “<strong>Instance Retention Graph”</strong>. Jest to graf przedstawiający łańcuchy obiektów wstrzymujących <strong>Garbage Collectora</strong> przed “skolekcjonowaniem” naszych obiektów. Analizując ten graf wypatrujemy wszystkich niepewnych połączeń, w naszym przypadku wygląda to tak:</span></span></p>
<p lang="zxx"><a href="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_5.png"><img class="aligncenter size-full wp-image-1803" src="http://xlab.pl/wp-content/uploads/2011/04/memory_leak_5.png" alt="" width="446" height="372" /></a></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Już pierwszy stopień od okna pokazuje kontrolkę <strong>WindowsFormsHost</strong>, co rodzi pytanie – dlaczego kontrolka będąca “dzieckiem” naszego okna miałaby niby blokować jego sprzątnięcie?</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Patrzymy “stopień wyżej” na klasę “<strong>WinFormsAdapter</strong>”, której pole <strong>_host</strong> zawiera referencję do naszego hosta – klasa ta nam zapewne za wiele nie mówi (co nie dziwi, gdyż jest to wewnętrzna klasa w <strong>WindowsFormsIntegration</strong>).</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Stopień wyżej widzimy klasę <strong>ProcessInputEventHandler</strong>, po nazwie i polu (<strong>_target</strong>) sądzić można, że metoda klasy <strong>WinFormsAdapter </strong>obsługuje zdarzenie <strong>PostProcessInput </strong>pochodzące z klasy <strong>InputManager</strong>.<br />
Gdyby bardziej zgłębić kalsę <strong>InputManagera </strong>– okazuje się, ze ma ona statyczne pole <strong>Current </strong>i do niego właśnie podpina się <strong>WindowsFormsHost</strong> za posrednictwem klasy <strong>WinFormsAdapter</strong>, z tego powodu referencja do kontrolki jest trzymana “na zawsze”, a co za tym idzie blokuje całe nasze okno. Co gorsza okno blokowało obiekt podpięty do <strong>DataContext</strong>, a obiekt ten mały zdecydowanie nie był!</span></span></p>
<p lang="zxx">
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Gdyby za każdym razem zanim użyje się kontrolki przestudiować MSDN można by zauważyć, że klasa dziedziczy po <strong>HwndHost</strong>, który jak wszyscy wiemy implementuje interfejs <strong>IDisposable</strong>&#8230; zaraz nie wszyscy? i wcale mnie to nie dziwi&#8230; w każdym razie &#8211;  jeżeli nawet pośrednio nasza kontrolka dziedziczy po <strong>IDisposable</strong>, to  po skończeniu pracy z naszą kontrolką wystarczy wywołać metodę <strong>Dispose()</strong> i wszystko będzie działać jak należy.</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small">Zmieniamy zatem naszą obsługę zdarzenia Closed na następującą:</span></span></p>
<p lang="zxx"><span style="color: #000000"> <span style="font-size: small">Closed += ((sender, e) =&gt;<br />
</span></span><span style="font-size: small">{<br />
</span><span style="color: #0000ff"><span style="font-size: small">this</span></span><span style="color: #000000"><span style="font-size: small">.<span style="color: #000000">host.Dispose();<br />
</span></span></span><span style="font-size: small"><span style="color: #000000">});</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">i wszystko gra – wykres zajmowanej pamięci właściwie się nie zmieni w porównaniu do poprzedniego (niepełnego) fixa, gdyż nasze okienko samo w sobie pamięci za wiele nie pochłania (brak zauważalnych efektów), ale już wynik działania profilera – owszem. Na liście klas nie znajdziemy już pozycji <em>MemoryTakingWindow </em>(pod warunkiem, że okienko nie jest otwarte podczas pobierania snapshota, oczywiście).</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><br />
</span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">Kilka wniosków na koniec:<br />
- Panowie z <strong>Red Gate </strong>mają głowy na karku. Wiedzą co programiści lubią – ich narzędzia są świetnie wykonane, bardzo funkcjonalne, a zarazem intuicyjne i estetyczne. W celu znalezienia mojego błędu nie potrzebowałem korzystać z żadnej dokumentacji, czy instrukcji. Wszystko wydawało się super-naturalne!</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- kontrolka <strong>WindowsFormsHost</strong> lubi zrobić psikusa. Należy pamiętać, że przy zamykaniu okna należy wywołać metodę <strong>Dispose</strong> (wg. informacji znalezionych &#8222;na Google&#8217;u&#8221; bywa tak, że trzeba ją najpierw jeszcze ręcznie usunąć z nadrzędnego grida, czy innego kontenera, jednak nie ręczę za prawdziwość tej informacji, tylko przestrzegam przed ewentualnością). Nie jest to wiedza “oczywista” i raczej wymaga przekazania informacji przez kogoś, bądź też kilku godzin męki – jak w moim przypadku.</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- WPF jest “fajny” i daje sporo możliwości, ale czyha tu na programistę wiele przykrych niespodzianek, które mogą napsuć krwi. Nie jest to jedyny tego przykład</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- teoretycznie winą programisty są konsekwencje nie zwolnienia zasobów i nie wywołania metody <strong>Dispose</strong> w klasie implementującej interfejs<strong> IDisposable</strong>.</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><br />
</span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">I&#8230; kilka usprawiedliwień:</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- kontrolka <strong>WindowsFormsHost</strong>, jak to przystało na kontrolkę <strong>WPF</strong> dodawana jest w <strong>XAML</strong>&#8216;u – a z tego poziomu raczej ciężko stwierdzić, że akurat <strong>TA</strong> kontrolka rozwija jakiś tam interfejs. Metod również nie zobaczymy w intelisensie &#8211; nawet przypadkiem&#8230;</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- oczywiście wypadało zajrzeć na dokumentację kontrolki przed jej użyciem – szczególnie takiej &#8222;wyjątkowej&#8221; – ale jak to już było wyżej zaznaczone, <strong>WindowsFormsHost</strong> nie implementuje <strong>IDisposable</strong> bezpośrednio, a poprzez klasę bazową, więc i w dokumentacji na pierwszy rzut oka nie widzimy nic nakierowującego nas.</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- podpinanie się pod zdarzenia statycznych pól jest generalnie mechanizmem &#8222;trochę dziwnym&#8221; i ryzykownym i dość często odradzanym. Jeśli o mnie chodzi – mam wrażenie, że kod pod <strong>WindowsFormsHost </strong>mógłby być napisany troszkę lepiej &#8211; w celu zniwelowania tego ryzyka.</span></span></span></p>
<p lang="zxx"><span style="font-size: small"><span style="color: #000000">- kontrolki implementujące interfejs <strong>IDisposable</strong> to rzadkość i raczej niewielu programistów spodziewa się takiego psikusa.</span></span></p>
<p lang="zxx"><span style="font-size: small"><span style="color: #000000">- Czytelnikowi wydać się może dziwne &#8211; przecież w przykładzie na pierwszy rzut oka widać, że to <strong>WidnowsFormsHost</strong> coś tu miesza, jednak w naszej prawdziwej aplikacji &#8211; jak to w życiu rzeczywistym &#8211; kontrolka nie rzucała się w oczy&#8230; była dodana do formatki pośrednio (stanowiła element innej kontrolki dodanej do okienka), ponadto stanowiła jedną z kilkudziesięciu kontrolek, a przy tym zdecydowanie nie istotna, pokazywała się tylko na kilka chwil i miała rozmiar kilkunastu px&#8230;)</span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- to nie ja dodałem kontrolkę do tamtego formularza ;)</span></span></span></p>
<p lang="zxx"><span style="color: #000000"><span style="font-size: small"><span style="color: #000000">- nadmierne pseudo-poczucie humoru we wpisie jest implikacją pory oraz dnia, w którym powstawał. Czyli &#8222;jakiś weekendowy wieczór&#8221; ;)</span></span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/net-i-memory-leak-czyli-dzien-z-zycia-programisty/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Dynamiczne tworzenie interfejsu użytkownika przy pomocy refleksji.</title>
		<link>http://xlab.pl/dynamiczne-tworzenie-interfejsu-uzytkownika-przy-pomocy-refleksji/</link>
		<comments>http://xlab.pl/dynamiczne-tworzenie-interfejsu-uzytkownika-przy-pomocy-refleksji/#comments</comments>
		<pubDate>Sat, 19 Feb 2011 07:47:16 +0000</pubDate>
		<dc:creator>Jarek Kożdoń</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[reflection]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=1762</guid>
		<description><![CDATA[Niedawno, przy okazji rozmyślania nad konstrukcją interfejsu użytkownika dla narzędzia tworzonego dla własnych potrzeb, przypomniał mi się pewien projekt, nad którym miałem okazję pracować. Projekt nie był wielki, ale naszpikowany ciekawymi rozwiązaniami, m.in. LINQ (zarówno dla bazy danych jak i LINQ to XML), SQL Server Compact Edition, przetwarzanie bardzo sporych XMLi. Było również jedno rozwiązanie, [...]]]></description>
			<content:encoded><![CDATA[<p>Niedawno, przy okazji rozmyślania nad konstrukcją interfejsu użytkownika dla narzędzia tworzonego dla własnych potrzeb, przypomniał mi się pewien projekt, nad którym miałem okazję pracować. Projekt nie był wielki, ale naszpikowany ciekawymi rozwiązaniami, m.in. LINQ (zarówno dla bazy danych jak i LINQ to XML), SQL Server Compact Edition, przetwarzanie bardzo sporych XMLi. Było również jedno rozwiązanie, które szczególnie zapadło mi w pamięci – kontrolka do edycji danych obiektów, co ciekawe – dla wszystkich obiektów bazodanowych (a było ich trochę, nie setki – ale powiedzmy kilkanaście) była tylko i wyłącznie jedna kontrolka. Nasuwa się tutaj pytanie „ale jak?!, przecież to musiało mieć milion linii kodu!”. Ale odpowiedź brzmi „wcale nie”. Z pomocą przyszła refleksja&#8230;</p>
<p>Zamieszczam więc niniejszym skromny instruktarz, który być może kogoś zainspiruje, do kodu kontrolki obecnie dostępu nie posiadam, przedstawię więc bardziej ideę jako propozycje alternatywy dla typowego myślenia o edycji właściwości naszych obiektów.</p>
<p style="padding-left: 30px"><strong>1. Co to jest refleksja?</strong></p>
<p>Dla tych co wiedzą – przypomnienie (bądź akapit do przeskrolowania), dla pozostałych – kilka podstawowych informacji.</p>
<p><strong>Refleksja </strong>to mechanizm pozwalający na pozyskiwanie informacji o klasach, czy kodzie skompilowanych już klas (na przykład właśnie wykonywanego programu, czy też odczytanych przez niego binarek).</p>
<p>W celu użycia refleksji w projekcie <strong>.NET</strong>owym należy użyć przestrzeń nazw <strong>System.Reflection</strong>. Dzięki temu będziemy mieli dostęp do podstawowych klas refleksji czyli: <strong>Type</strong>, <strong>MethodInfo</strong>, <strong>ProprtyInfo</strong>, <strong>EventInfo</strong>,	<strong> FieldInfo</strong>, <strong>ConstructorInfo</strong>&#8230; Każda odpowiada jednemu z elementów tworzących klasy.</p>
<p>Żeby pobrać informacje dotyczące obiektu danej klasy wywołać należy na nim metodę <strong>.GetType()</strong> dziedziczoną z bazowej klasy <strong>Object</strong>.</p>
<p style="padding-left: 30px"><strong>2. Skąd wiemy co wyświetlać?</strong></p>
<p>Metod na pozyskanie interesującej nas informacji jest co najmniej kilka. Możemy pozyskać informacje o klasie wczytując plik binarny i w nim szukając, możemy szukać po nazwie klasy i jej przestrzeni nazw, ale zdecydowanie najłatwiejszym sposobem jest wywołanie wspomnianej powyżej metody <strong>GetType()</strong> na obiekcie, który nas interesuje.</p>
<p>Co wyświetlać? O tym decydujemy już wyłącznie my! Powinniśmy jednak coś założyć, w tym przykładzie wyświetlać chciałbym wszystkie publiczne <strong>Property </strong>obiektów.</p>
<p>Skoro już wiemy jak pobrać typ obiektu oraz wiemy co będziemy wyświetlać pozostaje wyłącznie pobrać listę, nie jest to nic trudnego, wystarczy wywołać metodę GetProperties() klasy Type, która zwraca tablicę obiektów PropertyInfo danego typu. Stworzymy więc taki kod:</p>
<pre style="padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> type = ob.GetType();
</span></span><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties = type.GetProperties();
</span></span></pre>
<p>kod ten nie spełnia jednak naszego założenia, bowiem zwrócone zostaną <span style="text-decoration: underline">wszystkie</span> publiczne properties (domyślne działanie nie zwraca prywatnych właściwości!) łącznie z tymi statycznymi (chcemy tylko właściwości obiektu). W celu pozyskania odpowiedniej listy użyć należy przeładowania metody GetProperties wraz z argumentem w postaci wartości enuma <strong>BindingFlags</strong> (dopuszczając bitowe dodawanie wielu wartości)</p>
<pre style="padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> type = ob.GetType();
</span></span><span style="color: #0000ff"><span style="font-family: Consolas">var </span></span><span style="color: #000000"><span style="font-family: Consolas">properties = type.GetProperties(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Public | </span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Instance);

</span></span></pre>
<p>Lista gotowa!</p>
<p style="padding-left: 30px"><strong>3. A co jeżeli jakiegoś pola NIE chcę wyświetlać?</strong></p>
<p>Nie, nie trzeba w takim przypadku robić dziwnych warunków czy aby dane property jest jednym z wykluczonych, czy nie, dużo bardziej uniwersalnym sposobem jest użycie <strong>atrybutu</strong>. Można działać w 2 strony – stworzyć atrybut informujący o tym, że dane pole powinno być wyświetlane, bądź atrybut informujący o tym, że jego edycja nie jest potrzebna. Pokażę drugie rozwiązanie, jako bardziej ogólne i bardziej do mnie przemawiające, poza tym pozwalające w dalszej drodze edytować wartości obiektów nie należących do danego projektu.</p>
<p>Najpierw klasa atrybutu:</p>
<p style="padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">class</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">HiddenValueAttribute</span></span><span style="color: #000000"><span style="font-family: Consolas"> : <span style="color: #2b91af">Attribute</span><br />
{<br />
}</span></span></p>
<p>Po czym umieszczamy atrybut przy Property, którego nie chcemy widzieć:</p>
<p style="padding-left: 30px"><span style="font-family: Consolas">[</span><span style="color: #2b91af"><span style="font-family: Consolas">HiddenValue</span></span><span style="color: #000000"><span style="font-family: Consolas">]</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">string</span></span><span style="color: #000000"><span style="font-family: Consolas"> HiddenName { </span></span><span style="color: #0000ff"><span style="font-family: Consolas">get</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">set</span></span><span style="color: #000000"><span style="font-family: Consolas"> }</span></span></p>
<p>a teraz modyfikacja naszej metody pobierającej listę do wyświetlenia (dodajemy również jej nazwę):</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm"><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm"><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">IEnumerable</span></span><span style="color: #000000"><span style="font-family: Consolas">&lt;</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas">&gt; GetPropertiesToDisplay(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span></p>
<p style="padding-left: 30px"><span style="color: #000000"><span style="font-family: Consolas"> {</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
</span></span><span style="color: #0000ff"><span style="font-family: Consolas">var</span><span style="color: #000000"><span style="font-family: Consolas"> type = ob.GetType();</span></span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
var</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties = type.GetProperties(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Public | </span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Instance);</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
var</span></span><span style="color: #000000"><span style="font-family: Consolas"> returnValue = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">from</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> p </span></span><span style="color: #0000ff"><span style="font-family: Consolas">in</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties </span></span><span style="color: #0000ff"><span style="font-family: Consolas">where</span></span><span style="color: #000000"><span style="font-family: Consolas"> p.GetCustomAttributes(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">typeof</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">HiddenValueAttribute</span></span><span style="color: #000000"><span style="font-family: Consolas">), </span></span><span style="color: #0000ff"><span style="font-family: Consolas">true</span></span><span style="color: #000000"><span style="font-family: Consolas">).Length == 0 </span></span><span style="color: #0000ff"><span style="font-family: Consolas">select</span></span><span style="color: #000000"><span style="font-family: Consolas"> p;</span></span><br />
<span style="color: #000000"><span style="font-family: Consolas"> }</span></span></p>
<p><span style="color: #000000"><span style="font-family: Consolas"> </span></span></p>
<p><span style="color: #000000"><span style="font-family: Consolas"> </span></span></p>
<p>Jak widać dodana została linijka wyszukująca tylko te <strong>PropertyInfo</strong>, które wśród swoich atrybutów nie mają tego o typie <span style="color: #2b91af"><span style="font-family: Consolas">HiddenValueAttribute</span></span>, w celu tym użyta zostało użyte zapytanie <strong>LINQ</strong> wywołujące metodę <strong>GetCustomAttributes</strong>, która zwraca tablicę atrybutów spełniających warunki. Warunki podawane w argumentach to typ atrybutu (opcjonalny parametr, w drugim przeładowaniu metody nie występuje) oraz czy brać pod uwagę dziedziczone atrybuty.</p>
<p style="padding-left: 30px"><strong>4. Jak wyświetlać?</strong></p>
<p>Przechodzimy teraz do najistotniejszego punktu – wyświetlanie. Założymy, że wyświetlamy kontrolki na obiekcie klasy Panel o nazwie&#8230; panel!</p>
<p>Metoda wyświetlająca kosztować będzie nas najwięcej pracy – tutaj generalnie przewidzieć będziemy musieli wszystkie potencjalnie wyświetlane typy oraz obsługę każdego z nich.</p>
<p>Ale powoli.</p>
<p>Zacznijmy od organizacji naszego panelu, proponuję wyświetlać wartości w wierszach, w każdym etykieta z nazwą i odpowiednia kontrolka dla wartości &#8211; taka para dla każdej Property naszego obiektu. Czyli na przykład:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">void</span></span><span style="color: #000000"><span style="font-family: Consolas"> CreateControlsForProps(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">IEnumerable</span></span><span style="color: #000000"><span style="font-family: Consolas">&lt;</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas">&gt; properties, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
foreach</span></span><span style="color: #000000"><span style="font-family: Consolas"> (</span></span><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop </span></span><span style="color: #0000ff"><span style="font-family: Consolas">in</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties)<br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
Panel</span></span><span style="color: #000000"><span style="font-family: Consolas"> row = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Panel</span></span><span style="color: #000000"><span style="font-family: Consolas">();<br />
row.Dock = </span></span><span style="color: #2b91af"><span style="font-family: Consolas">DockStyle</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.Top;</span><br />
row.Height = 36;</span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span></p>
<p style="padding-left: 30px">this<span style="color: #000000"><span style="font-family: Consolas">.panel.Controls.Add(row);</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
row.Controls.Add(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="color: #000000"><span style="font-family: Consolas">.GetLabelForProperty(prop));</span></span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span></p>
<p style="padding-left: 30px">if<span style="color: #000000"><span style="font-family: Consolas"> (prop.PropertyType == </span></span><span style="color: #0000ff"><span style="font-family: Consolas">typeof</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">String</span></span><span style="color: #000000"><span style="font-family: Consolas">))</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
row.Controls.Add(</span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.GetInputForString(prop));</span><br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
else</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">if</span></span><span style="color: #000000"><span style="font-family: Consolas"> (prop.PropertyType == </span></span><span style="color: #0000ff"><span style="font-family: Consolas">typeof</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">Int32</span></span><span style="color: #000000"><span style="font-family: Consolas">))</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
row.Controls.Add(</span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.GetInputForNumber(prop));</span><br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
else</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">if</span></span><span style="color: #000000"><span style="font-family: Consolas"> (prop.PropertyType == </span></span><span style="color: #0000ff"><span style="font-family: Consolas">typeof</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">Color</span></span><span style="color: #000000"><span style="font-family: Consolas">))</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
row.Controls.Add(</span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.GetInputForColor(prop));</span><br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
else</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">if</span></span><span style="color: #000000"><span style="font-family: Consolas"> (prop.PropertyType.IsEnum)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
row.Controls.Add(</span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.GetInputForEnum(prop));</span><br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
else</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
row.Controls.Add(</span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Label</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">()</span><br />
{</span><span style="font-family: Consolas"><br />
Text = </span><span style="color: #a31515"><span style="font-family: Consolas">&#8222;Niestety, typu &#8222;</span></span><span style="color: #000000"><span style="font-family: Consolas"> + prop.PropertyType.Name + </span></span><span style="color: #a31515"><span style="font-family: Consolas">&#8221; jeszcze nie obsługujemy.&#8221;</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">,</span><br />
Left = row.Controls[0].Right + 15,</span><span style="font-family: Consolas"><br />
AutoSize = </span><span style="color: #0000ff"><span style="font-family: Consolas">true</span></span><span style="color: #000000"><span style="font-family: Consolas">,</span></span><span style="font-family: Consolas"><br />
Anchor = Anchor | </span><span style="color: #2b91af"><span style="font-family: Consolas">AnchorStyles</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">.Right</span><br />
});<br />
}<br />
}<br />
}</span></p>
<p><span style="color: #000000"><span style="font-family: Consolas"> </span></span></p>
<p>Tak przygotowany kod wystarczy „tylko” uzupełnić o metody tworzące odpowiednie kontrolki dla wprowadzania wartości i etykiety. Podam przykład dla klasy String, dla pozostałych typów odsyłam to pokładów własnej inwencji (nie jest to nic trudnego!):</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Control</span></span><span style="color: #000000"><span style="font-family: Consolas"> GetInputForString(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><br />
<span style="color: #2b91af"><span style="font-family: Consolas">TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="color: #000000"><span style="font-family: Consolas">tb.Left = 75;<br />
tb.Anchor = tb.Anchor | <span style="color: #2b91af">AnchorStyles</span>.Right;</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
return</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}</span></span></p>
<p>i dla etykiet:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Control</span></span><span style="color: #000000"><span style="font-family: Consolas"> GetLabelForProperty(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop)<br />
{</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
</span></span><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --><span style="color: #2b91af"><span style="font-family: Consolas">Label</span></span><span style="color: #000000"><span style="font-family: Consolas"> l = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Label</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="font-family: Consolas"><br />
l.Text = prop.Name;</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
return</span></span><span style="color: #000000"><span style="font-family: Consolas"> l;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}</span></span></p>
<p style="padding-left: 30px">
<p style="padding-left: 30px"><strong>5. A co z wartościami?!</strong></p>
<p>Bardzo dobre pytanie&#8230; jak widać&#8230; nic. Ale przecież nie po to tworzymy naszą kontrolkę do wyświetlania wartości, żeby wartości nie wyświetlać&#8230;</p>
<p>Dlatego konieczna będzie mała modyfikacja powyższego kodu. Zacznijmy od podstaw – jak w ogóle pobrać wartość Property obiektu, którego typu nie znamy z początku, zresztą sami przecież nie wiemy co to za Property (więc rzutowanie, czy wpisywanie nazwy Property po kropce nie jest możliwe)? Nic trudnego, w naszym kodzie mamy już obiekt opisujący Property, potrzebujemy jeszcze obiekt typu, którego dane Property dotyczy – a potem już tylko wywołanie metody GetValue:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm"><span style="font-family: Consolas">prop.GetValue(ob, </span><span style="color: #0000ff"><span style="font-family: Consolas">null</span></span><span style="color: #000000"><span style="font-family: Consolas">);</span></span></p>
<p>W naszym kodzie więc potrzebujemy obiektu, którego wartość chcemy pobierać, modyfikacje będą więc następujące:</p>
<p>Metoda tworząca kontrolkę do edycji/wyświetlania wartości:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Control</span></span><span style="color: #000000"><span style="font-family: Consolas"> GetInputForString(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
tb.Text = (</span></span><span style="color: #2b91af"><span style="font-family: Consolas">String</span></span><span style="color: #000000"><span style="font-family: Consolas">)prop.GetValue(ob, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">null</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">);</span>tb.Left = 75;<br />
tb.Anchor = tb.Anchor | <span style="color: #2b91af">AnchorStyles</span>.Right;</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
return</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}</span></span></p>
<p>I co za tym idzie uzupełnienie wywołań w głównej pętli wyświetlającej nasze wartości:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm"><span style="color: #000000"><span style="font-family: Consolas">row.Controls.Add(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">this</span></span><span style="color: #000000"><span style="font-family: Consolas">.GetInputForString(prop, ob));</span></span></p>
<p><span style="color: #000000"><span style="font-family: Consolas"> </span></span></p>
<p>i podobnie dla wszystkich pozostałych metod dotyczących Property. <strong> </strong></p>
<p style="padding-left: 30px"><strong>6. Ale opis jest brzydki&#8230;</strong></p>
<p>Fakt, opisy w tym momencie stanowią nazwy pól w klasie – brak spacji, często niewłaściwy język i skrótowe nazwy niewiele mówią potencjalnemu użytkownikowi. Tutaj z pomocą znowu przyjść nam mogą atrybuty.</p>
<p>Zacznijmy więc od zadeklarowania odpowiedniego (powinien zawierać przeładowany konstruktor oraz musi zawierać Property dla wyświetlanej wartości):</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">class</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">VisualDisplayAttribute</span></span><span style="color: #000000"><span style="font-family: Consolas"> : </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Attribute</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">string</span></span><span style="color: #000000"><span style="font-family: Consolas"> VisualDisplay { </span></span><span style="color: #0000ff"><span style="font-family: Consolas">get</span></span><span style="color: #000000"><span style="font-family: Consolas">; </span></span><span style="color: #0000ff"><span style="font-family: Consolas">set</span></span><span style="color: #000000"><span style="font-family: Consolas">; }</span></span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span></p>
<p style="padding-left: 30px">public<span style="color: #000000"><span style="font-family: Consolas"> VisualDisplayAttribute(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">string</span></span><span style="color: #000000"><span style="font-family: Consolas"> VisualDisplay)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
: </span></span><span style="color: #0000ff"><span style="font-family: Consolas">base</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">()</span><br />
{</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
this</span></span><span style="color: #000000"><span style="font-family: Consolas">.VisualDisplay = VisualDisplay;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}<br />
}</span></span></p>
<p>Następnie niewygodne Property „ozdabiamy” takim atrybutem:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="font-family: Consolas">[</span><span style="color: #2b91af"><span style="font-family: Consolas">VisualDisplay</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #a31515"><span style="font-family: Consolas">"Tło"</span></span><span style="color: #0000ff"><span style="font-family: Consolas">)]<br />
public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Color</span></span><span style="color: #000000"><span style="font-family: Consolas"> Background { </span></span><span style="color: #0000ff"><span style="font-family: Consolas">get</span></span><span style="color: #000000"><span style="font-family: Consolas">; </span></span><span style="color: #0000ff"><span style="font-family: Consolas">set</span></span><span style="color: #000000"><span style="font-family: Consolas">; }</span></span></p>
<p>I modyfikujemy tworzenie etykiety:</p>
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Control</span></span><span style="color: #000000"><span style="font-family: Consolas"> GetLabelForProperty(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
Label</span></span><span style="color: #000000"><span style="font-family: Consolas"> l = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Label</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
var</span></span><span style="color: #000000"><span style="font-family: Consolas"> attributes = prop.GetCustomAttributes(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">typeof</span></span><span style="color: #000000"><span style="font-family: Consolas">(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">VisualDisplayAttribute</span></span><span style="color: #000000"><span style="font-family: Consolas">), </span></span><span style="color: #0000ff"><span style="font-family: Consolas">true</span></span><span style="color: #000000"><span style="font-family: Consolas">);</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
if</span></span><span style="color: #000000"><span style="font-family: Consolas"> (attributes.Length &gt; 0)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="font-family: Consolas"><br />
l.Text = ((</span><span style="color: #2b91af"><span style="font-family: Consolas">VisualDisplayAttribute</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">)attributes[0]).VisualDisplay;</span><br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
else</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{<br />
</span>l.Text = prop.Name;<br />
}</span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
return</span></span><span style="color: #000000"><span style="font-family: Consolas"> l;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}</span></span> <strong><br />
</strong></p>
<p style="margin-bottom: 0cm;padding-left: 30px">
<p style="margin-bottom: 0cm;padding-left: 30px"><strong>7. Czy można zrobić pola tylko do 	odczytu? Albo obowiązkowe?</strong></p>
<p>Jak najbardziej – proponowane rozwiązanie to odpowiedni zestaw atrybutów. Np. nowy atrybut ReadOnlyValueAttribute, którego posiadanie przez Property badamy w identyczny sposób jak dla wcześniejszych przykładów i w przypadku znalezienia ustawiamy np. wartość enabled tworzonej kontrolki na false.</p>
<p>Dzięki odpowiedniemu zestawowi atrybutów możemy praktycznie dowolnie sterować całą naszą kontrolką – od możliwości edycji danej wartości, po kolor tła kontrolki, czy jej kontenera – granicą jest chyba tylko nasza wyobraźnia. Faktem jest, że pewne rzeczy dużo łatwiej było by zaprojektować w &#8222;tradycyjny&#8221; sposób, ustawiając kontrolki w designerze, niż odczytywać wartości z atrybutów pól klasy, po czym przeliczać je na wartości, które &#8222;ręcznie&#8221; trzeba ustawić w kontrolkach, granicę opłacalności wyznaczyć musimy sobie sami. <strong> </strong></p>
<p style="padding-left: 30px"><strong>8. Zaraz, zaraz&#8230; miała być edycja!</strong></p>
<p>I nikt o niej nie zapomniał. Jak łatwo zauważyć – wartości co prawda odczytujemy&#8230; ale ich już nie zmieniamy&#8230; metod jest kilka, ale wszystkie wymagają jednego – zapamiętania lub pozyskania obiektu PropertyInfo oraz obiektu, który wyświetlamy / edytujemy. Kiedy już owe obiekty mamy, wystarczy nam&#8230; jak zwykle jedna linijka&#8230; a dokładniej wywołanie metody SetValue klasy PropertyInfo</p>
<p>Zmodyfikujmy raz jeszcze nasz kod – do pól Tag paneli przypiszemy odpowiednie informacje (dla obiektu panel naturalny będzie obiekt na panelu wyświetlany, dla panelu wiersza – PropertyInfo, którego wiersz dotyczy):</p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas">void</span></span><span style="color: #000000"><span style="font-family: Consolas"> CreateControlsForProps(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">IEnumerable</span></span><span style="color: #000000"><span style="font-family: Consolas">&lt;</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas">&gt; properties, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
this</span></span><span style="color: #000000"><span style="font-family: Consolas">.panel.Tag = ob;</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
foreach</span></span><span style="color: #000000"><span style="font-family: Consolas"> (</span></span><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop </span></span><span style="color: #0000ff"><span style="font-family: Consolas">in</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
Panel</span></span><span style="color: #000000"><span style="font-family: Consolas"> row = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Panel</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
row.Tag = prop;<br />
&#8230;</span></span></p>
<p>Dodajmy obsługę zdarzenia zmiany wartości kontrolki edytującej Property, na przykład:</p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">private</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">Control</span></span><span style="color: #000000"><span style="font-family: Consolas"> GetInputForString(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas">();</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
tb.Text = (</span></span><span style="color: #2b91af"><span style="font-family: Consolas">String</span></span><span style="color: #000000"><span style="font-family: Consolas">)prop.GetValue(ob, </span></span><span style="color: #0000ff"><span style="font-family: Consolas">null</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">);</span><br />
tb.Left = 75;</span><span style="font-family: Consolas"><br />
tb.TextChanged += </span><span style="color: #0000ff"><span style="font-family: Consolas">new</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">EventHandler</span></span><span style="color: #000000"><span style="font-family: Consolas">(tb_TextChanged);</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
return</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb;</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
}</span></span></p>
<p style="margin-bottom: 0cm;padding-left: 30px"><span style="color: #0000ff"><span style="font-family: Consolas">void</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb_TextChanged(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> sender, </span></span><span style="color: #2b91af"><span style="font-family: Consolas">EventArgs</span></span><span style="color: #000000"><span style="font-family: Consolas"> e)</span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
{</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas"> tb = sender </span></span><span style="color: #0000ff"><span style="font-family: Consolas">as</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">TextBox</span></span><span style="color: #000000"><span style="font-family: Consolas">;</span></span><span style="color: #2b91af"><span style="font-family: Consolas"><br />
PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> prop = tb.Parent.Tag </span></span><span style="color: #0000ff"><span style="font-family: Consolas">as</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas">;</span></span><span style="color: #0000ff"><span style="font-family: Consolas"><br />
object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob = tb.Parent.Parent.Tag;</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span></p>
<p style="padding-left: 30px">prop.SetValue(ob, tb.Text, <span style="color: #0000ff"><span style="font-family: Consolas">null</span></span><span style="font-family: Consolas"><span style="font-family: Consolas">);</span><br />
}</span></p>
<p>Gotowe!</p>
<p><em>Zdaję sobie sprawę, że posługiwanie się polem Tag bywa mętne i trochę utrudnia analizę kodu następcom, ale zostało użyte raczej jako przykład niż wzór – osobiście proponowałbym np. podziedziczyć po panelu i stworzyć klasę panelu wiersza z odpowiednim, dedykowanym Property dla PropertyIfno itp. Takie rozwiązanie będzie dużo bardziej czytelne no i nikt nam wtedy wartości nie nadpisze, gdy stwierdzi, że fajnie by było dla niego przechować coś w Tagu</em> <strong> </strong></p>
<p style="padding-left: 30px"><strong>9.Przecież refleksja jest wolna!</strong></p>
<p>Tak, refleksja działa wolniej niż pobierania i ustawianie wartości &#8222;normalnymi&#8221; odwołaniami do właściwości obiektów, jednak stworzenie i wyświetlenie jednej kontrolki zajmuje nieporównanie więcej czasu&#8230; więc nie stanowi to w tym przypadku żadnego argumentu, ani nie powinno nas to napełniać obawami. <strong> </strong></p>
<p style="padding-left: 30px"><strong>10. Plus i minus, to jedyne co słyszę 	– czyli kiedy stosować?</strong></p>
<p>Zdecydowanym plusem takiego rozwiązania jest jego elastyczność, można wyświetlić w ten sposób wszystko. Dosłownie. Wystarczy spojrzeć na Visualowe komponenty do edycji obiektów – PropertyGrid&#8217;y, które mają bardzo szerokie możliwości, a działają na dokładnie takiej samej zasadzie. Będzie to rozwiązanie szczególnie cenne, kiedy klasy wyświetlane zmieniają się co chwila, albo interfejs powstaje w celu edycji danych, których jeszcze nie znamy.</p>
<p>Kolejnym plusem jest modna „reusability”, jeżeli stworzymy dobrze taką kontrolkę oraz zestaw atrybutów użycie ich w kolejnym projekcie będzie dziecinnie proste – w końcu nie mamy żadnych odwołań do klas encji biznesowych, czy jakichkolwiek innych klas, które chcemy wyświetlać.</p>
<p>Oczywiście są i minusy&#8230;<br />
M.in. dużo cięższe debugowanie wymuszone przez użytą refleksję.</p>
<p>Brak możliwości podejrzenia jak wygląda kontrolka w trybie design, jedyna możliwość to uruchomienie aplikacji na przykładowych danych.</p>
<p>Monotonność interfejsu i dużo trudniejsze modyfikacje wyglądu kontrolek pod konkretne Propery. Bez napracowania się nad atrybutami i ich interpretacją każde użycie kontrolki do wyświetlania danych wyglądać będzie identycznie.</p>
<p>Można zadać sobie pytanie po co tak się męczyć? przecież są wspomniane już PropertyGrid&#8217;y, są dobre do edycji danych Gridy. Ciężko temu argumentowi zaprzeczyć, to prawda. Tym niemniej tych gridów nie zmodyfikujemy, nie powiemy im co mają wyświetlać, a co nie w tak łatwy sposób itp. To rozwiązanie da nam pełną dowolność, której być może będziemy potrzebować.</p>
<div style="width: 1px;height: 1px;overflow: hidden">
<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } --></p>
<p style="margin-bottom: 0cm"><span style="font-size: small"><span style="color: #0000ff"><span style="font-family: Consolas">public</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">IEnumerable</span></span><span style="color: #000000"><span style="font-family: Consolas">&lt;</span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas">&gt; GetPropertiesToDisplay(</span></span><span style="color: #0000ff"><span style="font-family: Consolas">object</span></span><span style="color: #000000"><span style="font-family: Consolas"> ob)</span></span></span></p>
<p style="margin-bottom: 0cm"><span style="color: #000000"><span style="font-family: Consolas"><span style="font-size: small">{</span></span></span></p>
<p style="margin-bottom: 0cm"><span style="color: #000000"> </span><span style="font-size: small"><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> type = ob.GetType();</span></span></span></p>
<p style="margin-bottom: 0cm"><span style="color: #000000"> </span><span style="font-size: small"><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties = type.GetProperties(</span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Public | </span></span><span style="color: #2b91af"><span style="font-family: Consolas">BindingFlags</span></span><span style="color: #000000"><span style="font-family: Consolas">.Instance);</span></span></span></p>
<p style="margin-bottom: 0cm"><span style="color: #000000"> </span><span style="font-size: small"><span style="color: #0000ff"><span style="font-family: Consolas">var</span></span><span style="color: #000000"><span style="font-family: Consolas"> returnValue = </span></span><span style="color: #0000ff"><span style="font-family: Consolas">from</span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas">PropertyInfo</span></span><span style="color: #000000"><span style="font-family: Consolas"> p </span></span><span style="color: #0000ff"><span style="font-family: Consolas">in</span></span><span style="color: #000000"><span style="font-family: Consolas"> properties </span></span><span style="color: #0000ff"><span style="font-family: Consolas">where</span></span><span style="color: #000000"><span style="font-family: Consolas"> p.GetCustomAttributes(</span></span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #2b91af"><span style="font-family: Consolas"> </span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span><span style="color: #000000"><span style="font-family: Consolas"> </span></span><span style="color: #0000ff"><span style="font-family: Consolas"> </span></span><span style="color: #000000"><span style="font-family: Consolas"><br />
</span></span></span></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/dynamiczne-tworzenie-interfejsu-uzytkownika-przy-pomocy-refleksji/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Insight w programowanie msejf: .NET</title>
		<link>http://xlab.pl/insight-w-programowanie-msejf-net/</link>
		<comments>http://xlab.pl/insight-w-programowanie-msejf-net/#comments</comments>
		<pubDate>Mon, 17 May 2010 08:19:35 +0000</pubDate>
		<dc:creator>jaroslaw.kroczek</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[msejf]]></category>
		<category><![CDATA[programowanie]]></category>
		<category><![CDATA[projektowanie]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=1071</guid>
		<description><![CDATA[Poniższym wpisem chcielibyśmy rozpocząć serię postów dedykowanych technologiom, w jakich tworzymy aplikację msejf. Projekt i jego poszczególne elementy wymagają połączenia różnych rozwiązań i dzięki temu jest wyjątkowo ciekawy z punktu widzenia programistów i web developerów. Cykl chcielibyśmy zacząć od przyjrzenia się technologii .NET, w oparciu o którą zbudowaliśmy część desktopową aplikacji. Spośród typowych bibliotek tej [...]]]></description>
			<content:encoded><![CDATA[<p>Poniższym wpisem chcielibyśmy rozpocząć serię postów dedykowanych  technologiom, w jakich tworzymy aplikację msejf. Projekt i jego  poszczególne elementy wymagają połączenia różnych rozwiązań i dzięki  temu jest wyjątkowo ciekawy z punktu widzenia programistów i web  developerów.</p>
<p>Cykl chcielibyśmy zacząć od przyjrzenia się technologii .NET, w  oparciu o którą zbudowaliśmy część desktopową aplikacji. Spośród  typowych bibliotek tej platformy z których korzystaliśmy szczególnie  dwie zasługują na szczególną uwagę: WPF i WCF.</p>
<p>WPF (Windows Presentation Foundation) to silnik graficzny bazujący na  platformie .NET od wersji 3.0. Co takiego ciekawego jest w WPF, że  postanowiliśmy użyć jej do naszej aplikacji? WPF daje nam ogromne  możliwości co do kształtowania wyglądu aplikacji. msejf ma być  niebanalny, a jeśli tak, to WPF jest naturalnym wyborem. Tworząc  interfejs użytkownika praktycznie nie musimy się niczym ograniczać. Nie  musimy martwić się o to, że nie będziemy w stanie przełożyć kreatywności  naszych grafików na działającą aplikację.</p>
<p>Dla nas, programistów, WPF ma też inne zalety. Przede wszystkim, WPF  zmienia całkowicie sposób implementacji aplikacji desktopowych,  zbliżając się stylem do aplikacji webowych. Nasze aplikacje oparte są o  wzorzec projektowy Model-View-ViewModel, co skutkuje przejrzystym i  łatwiejszym w utrzymaniu kodem.</p>
<p>WCF to drugie w kolejności ciekawe rozwiązanie, w oparciu o które  zbudowaliśmy klienta msejf. WCF (Windows Communication Foundation) to  część .NET Framework’a, która dostarcza ujednolicony model  programistyczny dla aplikacji opartych o usługi. Większości będzie się  to zapewne kojarzyć z komunikacją z zewnętrznymi serwisami. My  wykorzystujemy WCF do komunikacji międzyprocesowej. Technologia  znakomicie sprawdza się w tej roli, upraszczając wymianę informacji  między komponentami. Jej zastosowanie daje nam też duże możliwości  łatwej zmiany konfiguracji oraz monitorowania pracy komponentów dzięki  wbudowanym mechanizmom logowania.</p>
<p>Co jeszcze w msejf desktop zasługuje na szczególną uwagę?  Zastosowaliśmy mnóstwo ciekawych  rozwiązań. Długo zastanawialiśmy się  nad wyborem optymalnej architektury, co zaowocowało sprawnie działającą,  łatwą w utrzymaniu i stabilną aplikacją. Na każdym etapie prac  staraliśmy się trzymać najlepszych praktyk wytwarzania i projektowania  oprogramowania.</p>
<p>msejf desktop to nie tylko ciekawe technologie, ale przede wszystkim  innowacyjna aplikacja, a efekt końcowy naszych prac będzie można już  wkrótce podziwiać.</p>
<p>źródło: <a title="blog.msejf.pl" href="http://blog.msejf.pl/">blog.msejf.pl</a></p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/insight-w-programowanie-msejf-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jak w projekcie skorzystać z bazy SQLite</title>
		<link>http://xlab.pl/jak-w-projekcie-skorzystac-z-bazy-sqlite/</link>
		<comments>http://xlab.pl/jak-w-projekcie-skorzystac-z-bazy-sqlite/#comments</comments>
		<pubDate>Tue, 27 Apr 2010 21:16:14 +0000</pubDate>
		<dc:creator>Krzysztof Wawoczny</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[SQLite]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=973</guid>
		<description><![CDATA[Zazwyczaj w tworzonych projektach trzeba korzystać z bazy danych, wybór konkretnej zależy od rodzaju projektu &#8211; dla ćwiczebnych aplikacji, polecam SQLite. Cała konfiguracja nie powinna zająć więcej czasu niż ugotowanie jajek. Po pierwsze należy ściągnąć i zainstalować pakiet ADO.NET z http://sqlite.phxsoftware.com/ (lub skorzystać z innego ;)) Po drugie do projektu dodajemy referencję do System.Data.SQLite z [...]]]></description>
			<content:encoded><![CDATA[<p>Zazwyczaj w tworzonych projektach trzeba korzystać z bazy danych, wybór konkretnej zależy od rodzaju projektu &#8211; dla ćwiczebnych aplikacji, polecam SQLite. Cała konfiguracja nie powinna zająć więcej czasu niż ugotowanie jajek.</p>
<p>Po pierwsze należy ściągnąć i zainstalować pakiet ADO.NET z <a href="http://sqlite.phxsoftware.com/">http://sqlite.phxsoftware.com/</a> (lub skorzystać z innego ;))</p>
<p>Po drugie do projektu dodajemy referencję do System.Data.SQLite z pakietu ADO.NET (kopiujemy do katalogu System.Data.SQLite.dll)</p>
<p>Po trzecie dodajemy do projektu plik *.config (opis na <a href="http://msdn.microsoft.com/en-us/library/ms184658%28VS.80%29.aspx">http://msdn.microsoft.com/en-us/library/ms184658%28VS.80%29.aspx</a>) oraz w pliku *.config wpisujemy:</p>
<pre name="code" class="php">
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SQLite"/>
      <add name="SQLite Data Provider" invariant="System.Data.SQLite"
           description=".Net Framework Data Provider for SQLite"           type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
</configuration>
</pre>
<p>Po czwarte należy wyposażyć się w jakiegoś managera bazy danych, polecam wtyczkę do przeglądarki firefox <a href="http://code.google.com/p/sqlite-manager/">http://code.google.com/p/sqlite-manager/</a></p>
<p>Po piąte wyklikujemy prostą bazę danych</p>
<p>Po szóste &#8211; gotowe ; )</p>
<p>Teraz test naszej bazy:</p>
<pre name="code" class="php">
      DbProviderFactory fact = DbProviderFactories.GetFactory("System.Data.SQLite");
      using (DbConnection cnn = fact.CreateConnection())
      {
        cnn.ConnectionString = "Data Source=test.db3";
        cnn.Open();
      }
</pre>
<p>Jeśli nie dostaliśmy żadnego błędu to cała konfiguracja przebiegła pomyślnie.</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/jak-w-projekcie-skorzystac-z-bazy-sqlite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Najprostszy sposób na zalogowanie użytkownika</title>
		<link>http://xlab.pl/najprostszy-sposob-na-zalogowanie-uzytkownika/</link>
		<comments>http://xlab.pl/najprostszy-sposob-na-zalogowanie-uzytkownika/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 19:33:33 +0000</pubDate>
		<dc:creator>Krzysztof Wawoczny</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[projektowanie]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=962</guid>
		<description><![CDATA[Obecnie, w niemal każdej aplikacji biznesowej wymagane jest zalogowanie się, by w pełni móc korzystać z możliwości, jakie taka aplikacja daje, lub by wogóle móc cokolwiek zrobić. Jakiś czas temu zrobiłem krótki research po sieci w poszukiwaniu jakiegoś sprytniejszego rozwiązania niż to, które używam w swoich aplikacjach. Cóż&#8230; Dziwni są ludzie, którzy zatrudniają do obrony [...]]]></description>
			<content:encoded><![CDATA[<p>Obecnie, w niemal każdej aplikacji biznesowej wymagane jest zalogowanie się, by w pełni móc korzystać z możliwości, jakie taka aplikacja daje, lub by wogóle móc cokolwiek zrobić. Jakiś czas temu zrobiłem krótki research po sieci w poszukiwaniu jakiegoś sprytniejszego rozwiązania niż to, które używam w swoich aplikacjach. Cóż&#8230; Dziwni są ludzie, którzy zatrudniają do obrony swojego zamku legiony, a pozwalają do niej wejść zwykłym OR 1=1 (to tak na marginesie), nie rozumię też rozwiązania, które zostało pozytywnie ocenione na jednym z for programistycznych, a wygląda ono tak:<br />
W aplikacji sprawdzamy, czy ustawiony jest w bazie znacznik informujący o zalogowaniu, jeśli nie, to po zalogowaniu generujemy go, a usuwamy, gdy użytkownik zamknie aplikację&#8230; A co, jeśli zwiesi się komp, zabraknie prądu albo wydarzy się coś innego? Przecież po wystąpieniu tak nieoczekiwanego zdarzenia wartość w bazie może się nie zmienić, a wtedy każdy, kto skorzysta z komputera będzie zalogowany.  Naprawdę nie rozumię wielu tych wielkich idei, dlatego na razie nadal korzystam z bardzo prostego rozwiązania, które wygląda następująco:</p>
<p>W aplikacji w sekcji odpowiedzialnej za przechowanie predefiniowanych zmiennych globalnych (jak np. nazwa bazy, string wyświetlany w górnej belce aplikacji etc.) ustawiam sobie zmienną, określającą, czy użytkownik jest zalogowany (domyślnie ustawioną na false) oraz metodę pozwalającą zmienić wartość tej zmiennej:</p>
<pre name="code" class="php">public class GlobalAppVariables
{
    /// Globalna zmienna, której wartość jest ustwaiona na 1, gdy użytkownik się zaloguje.
    static int _logged = 0;

    /// Dostęp/zmiana wartości globalnej zmiennej _logged
    public static int Logged
    {
      get
      {
        return _logged;
      }
      set
      {
        _logged = value;
      }
    }
}</pre>
<p>Samo logowanie polega na wywołaniu metody, która połączy się z bazą, sprawdzi, czy dla podanych parametrów istnieje wpis i  na tej podstawie zwróci wynik pozytywny/negatywny, co z kolei pozwoli mi ustawić wartość zmiennej _logged w następujący sposób:</p>
<pre name="code" class="php">private void button1_Click(object sender, EventArgs e)
{
    object result = Queries.StartSession(this.loginTxt.Text, this.PasswordTxt.Text);
   //Queries to osobna klasa, w której przechowywane są metody odpowiedzialne za operacje na bazie
    if (result != null)
    {
        this.Close(); //zamknięcie okna logowania
        GlobalAppVariables.Logged = 1; // w tej chwili wiem, że już mam zalogowanego użytkownika
    }
    else
    {
       //info o nieudanym logowaniu
    }
}</pre>
<p>Jeśli już mam zalogowanego użytkownika, mogę odblokować domyślnie wyłączone opcje, lub zrobić coś innego.<br />
Jeśli nie potrzebujesz wymyślnego systemu logowania skorzystaj z przedstawionego sposobu. Jest on wystarczający dla wielu nieskomplikowanych aplikacji. AVE!</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/najprostszy-sposob-na-zalogowanie-uzytkownika/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dynamiczne generowanie kontrolek</title>
		<link>http://xlab.pl/dynamiczne-generowanie-kontrolek/</link>
		<comments>http://xlab.pl/dynamiczne-generowanie-kontrolek/#comments</comments>
		<pubDate>Fri, 23 Apr 2010 23:02:41 +0000</pubDate>
		<dc:creator>Krzysztof Wawoczny</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[c# kontrolki]]></category>
		<category><![CDATA[projektowanie]]></category>

		<guid isPermaLink="false">http://xlab.pl/?p=946</guid>
		<description><![CDATA[W czasie pracy nad swoim małym projektem w C#, stanąłem przed problemem dynamicznego generowania kontrolek na formie. Nie chciałem, aby cały kod za to odpowiedzialny znajdował się w zdarzeniu kliknięcia w button, wiec stworzyłem przykładową klasę, którą nazwałem ControlGenerator. Generalnie, trzeba by ją jakoś połączyć z główną formą aplikacji (w projekcie Form1 &#8211; standardowe nazewnictwo, [...]]]></description>
			<content:encoded><![CDATA[<p>W czasie pracy nad swoim małym projektem w C#, stanąłem przed problemem dynamicznego generowania kontrolek na formie. Nie chciałem, aby cały kod za to odpowiedzialny znajdował się w zdarzeniu kliknięcia w button, wiec stworzyłem przykładową klasę, którą nazwałem ControlGenerator.<br />
<a rel="attachment wp-att-947" href="http://xlab.pl/2010/04/dynamiczne-generowanie-kontrolek/klasa/"><img class="aligncenter size-full wp-image-947" title="klasa" src="http://xlab.pl/wp-content/uploads/2010/04/klasa.jpg" alt="klasa" width="241" height="40" /></a><br />
Generalnie, trzeba by ją jakoś połączyć z główną formą aplikacji (w projekcie Form1 &#8211; standardowe nazewnictwo, gdyż więcej form nie przewiduję). W klasie ControlGenerator utworzyłem zmienną typu Form1 służącą za łącznik klasa &#8211; forma:</p>
<pre class="php">public class ControlGenerator
{
    /// Prywatna zmienna typu Form1
    private Form1 pf;
   //...
}</pre>
<p>Następnie, konstruktor klasy musi posiadać takie przypisanie zmienej pf, aby wskazywała ona na referencję instancji mojej Form1 (trochę to może zamieszane, więc kawałek kodu wyjaśni, co miałem na myśli):</p>
<pre class="php">public ControlGenerator(Form1 f1)
{
  pf = f1;
}</pre>
<p>Tak właśnie wygląda konstruktor, o którym była mowa, a jak to wygląda &#8216;na żywo&#8217; jest ukazane poniżej.</p>
<p>W formie głównej aplikacji (Form1) po kliknięciu w jeden z przycisków powinny wygenerować się kontrolki, inicjuję więc obiekt klasy ControlGenerator w następujący sposób:</p>
<pre class="php">private void button1_Click(object sender, EventArgs e)
{
    ControlGenerator generate = new ControlGenerator(this);
   // właśnie tu do konstruktora przekazuje referencję do Form1 za pomocą this
}</pre>
<p>Skoro moje połączenie klasa &#8211; forma jest już aktywne, to pora napisać metodę generującą kontrolki. Do owej metody powinna być przekazana informacja jak wiele kontrolek utworzyć. W poniższym przykładzie ograniczę się do wygenerowania TextBoxów z Labelkami zawartymi w GroupBoxie (które mogą być oczywiście dodatkowo osadzone na jakimś panelu, czy czymkolwiek się chce).<br />
Gotowa funkcja prezentuje się następująco:</p>
<pre class="php">    public void GenerateRegisterControls(int number, string text)
    {
      int[] textboxes = new int[number];
      string[] labels = { "Imię", "Nazwisko", "PESEL", "Ulica", "Numer budynku",
                              "Miasto", "Kod pocztowy", "Województwo", "Telefon" };
      int i = 0, move = 0;

      //tworzę GroupBoxa, do którego wrzucę tworzone kontrolki (opis metody w następnym listingu)
      GroupBox box = GenerateGroupBoxControl(text); 

      foreach (int element in textboxes)
      {
        TextBox textbox = new TextBox(); //tworzę nowego TextBoxa
        Label label = new Label(); //tworzę nowy Label
        //lokalizacja TextBoxa
        textbox.Location = new System.Drawing.Point(200, 70 + move);
        textbox.Name = "textbox" + i.ToString();
        textbox.Size = new System.Drawing.Size(360, 20 + move); //wymiary TextBoxa
        //Rozmiar czcionki w TextBoxie - funkcja nie zostanie przedstawiona
        //w tym wpisie
        textbox.Font = SetFontForElement(40, textbox.Font);
        textbox.TabIndex = i;
        textbox.Visible = true;
        //automatyczna zmiana rozmiarów TextBoxa przy zmianie rozmiaru okna
        textbox.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
        textbox.BorderStyle = BorderStyle.FixedSingle; //styl ramki
        //lokalizacja Labela
        label.Location = new System.Drawing.Point(20, 80 + move);
        label.Name = "label" + i.ToString();
        //nazwa Labela wzięta z wcześniej utworzonej tablicy stringów
        label.Text = labels[i];
        label.Font = SetFontForElement(28, label.Font);
        label.Size = new System.Drawing.Size(160, 28);
        label.Visible = true;

        box.Controls.Add(textbox); //dodaję do GroupBoxa utworzone TextBoxy
        box.Controls.Add(label); //dodaję do GroupBoxa utworzone Labele

        i++;
        move += 50;
      }
      //dodaję GroupBoxa z kontrolkami do panelu w kontenerze Form1
      pf.splitContainer1.Panel2.Controls.Add(box);
    }</pre>
<p>Jak widać funkcja nie jest specjalnie skomplikowana, a tablicę z nazwami labelek można by przekazać jako parametr &#8211; jednak nie ma potrzeby w tym wpisie rozmieniać się na drobne. Tworzenie TextBoxów i Labelek można by dodatkowo zostawić osobnym funkcjom wywołanym w GenerateRegisterControls, jak np. GenerateGroupBoxControl, która wygląda następująco:</p>
<pre class="php">    private GroupBox GenerateGroupBoxControl(string text)
    {
      GroupBox box = new GroupBox();

      box.Name = "GroupBoxRegister";
      box.Text = text;
      box.Location = new System.Drawing.Point(1, 9);
      box.Size = new System.Drawing.Size(pf.splitContainer1.Panel2.Width - 20, pf.splitContainer1.Panel2.Height - 20);
      box.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;

      return box;
    }</pre>
<p>Samo wygenerowanie kontrolek po kliknięciu w jeden z przycisków wygląda następująco:</p>
<pre class="php">    private void button1_Click(object sender, EventArgs e)
    {
      ControlGenerator generate = new ControlGenerator(this);
      //9 TextBoxów i 9 Labelek, GroupBox będzie opatrzony tekstem Rejestracja
      generate.GenerateRegisterControls(9, "Rejestracja");
    }</pre>
<p>Efekt:<br />
<a rel="attachment wp-att-948" href="http://xlab.pl/2010/04/dynamiczne-generowanie-kontrolek/efekt/"><img class="aligncenter size-full wp-image-948" title="efekt" src="http://xlab.pl/wp-content/uploads/2010/04/efekt.jpg" alt="efekt" width="648" height="531" /></a></p>
<p>Jeśli ktoś dopiero zaczyna swoją przygodę z C#, to informacje, które przedstawiłem z pewnością się przydadzą, albo przynajmniej wskażą drogę poszukiwań w google. AVE!</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/dynamiczne-generowanie-kontrolek/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pobranie parametrów metody w C# wraz z wartościami</title>
		<link>http://xlab.pl/pobranie-parametrow-metody-w-c-wraz-z-wartosciami/</link>
		<comments>http://xlab.pl/pobranie-parametrow-metody-w-c-wraz-z-wartosciami/#comments</comments>
		<pubDate>Mon, 12 Oct 2009 15:44:32 +0000</pubDate>
		<dc:creator>Mateusz Kubiczek</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[reflection]]></category>

		<guid isPermaLink="false">http://www.xlab.pl/?p=558</guid>
		<description><![CDATA[Dosyć długo szukałem w jaki sposób pobrać nazwy parametrów metody wraz z ich wartościami w sposób uniwersalny. Ułatwiłoby to logowanie wszystkiego, co zachodzi w aplikacji. Wywołując metodę: public void CountPrice(int bar, string baz) { } chciałbym otrzymać w logach wpis: Method&#8217;s Foo arguments >> bar: 1, baz: zzz Najpierw spróbowałem za pomocą metody GetParameters klasy [...]]]></description>
			<content:encoded><![CDATA[<p>Dosyć długo szukałem w jaki sposób pobrać <em>nazwy</em> parametrów metody wraz z ich <em>wartościami</em> w sposób uniwersalny.</p>
<p>Ułatwiłoby to logowanie wszystkiego, co zachodzi w aplikacji. Wywołując metodę:</p>
<pre name="code" class="c-sharp">
public void CountPrice(int bar, string baz)
{

}</pre>
<p>chciałbym otrzymać w logach wpis:</p>
<blockquote><p>Method&#8217;s Foo arguments >> bar: 1, baz: zzz</p></blockquote>
<p><span id="more-558"></span></p>
<p>Najpierw spróbowałem za pomocą metody <a href="http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.getparameters.aspx"><strong>GetParameters</strong> klasy <strong>MethodInfo</strong></a>. Zwrócone obiekty typu <strong>ParameterInfo</strong> zawierają jednak tylko informacje o typach parametrów &#8211; nie mają wartości tych parametrów w czasie wykonywania kodu.</p>
<p>Moim celem było stworzenie metody, którą mógłbym użyć do pobrania sformatowanej informacji o parametrach metody &#8211; na przykład w celu zalogowania ich. Załóżmy dla prostoty testowania, że nasza metoda <strong>Foo</strong> będzie zwracała sformatowany napis z jej parametrami i ich wartościami.</p>
<p>Pierwsza wersja:</p>
<pre name="code" class="c-sharp">
public class TestClass
{
  public static string Foo(int bar, string baz)
  {
    return LogingHelpers.GetMethodArguments();
  }
}

public class LoggingHelpers
{
  public static string GetMethodArguments()
  {
    //TODO tutaj magia :-)
    return "";
  }
}</pre>
<p>Niestety &#8211; z taką składnią nie udało mi się. Z kontekstu <strong>LoggingHelpers.GetMethodArguments</strong> nie da się (lub nadal nie potrafię :-) ) dostać się do parametrów metody wywołującej. Działająca składnia jest nieco inna i odrobinę mniej wygodna:</p>
<pre name="code" class="c-sharp">
public class TestClass
{
  public static string Foo(int bar, string baz)
  {
    return GetMethodArguments(() => bar, () => baz);
  }

  public static string NoParameters()
  {
    return GetMethodArguments();
  }
}

public class LoggingHelpers
{
  public static string GetMethodArguments(params Func&lt;object&gt;[] expr)
  {
    //TODO tutaj magia, ujawnione już za chwilę!
    return "";
  }
}</pre>
<p>Ale najpierw test z wykorzystaniem NUnit.</p>
<pre name="code" class="c-sharp">
    using NUnit.Framework;
    using NUnit.Framework.SyntaxHelpers;

    [TestFixture]
    public class LoggingTests
    {

        [Test]
        public void TwoParametersCorrectlyFormatted
        {
            string parameterNamesAndValues = TestClass.Foo(1, "zzz");
            Assert.That(parameterNamesAndValues, Is.EqualTo("Method's Foo arguments >> bar: 1, baz: zzz");
        }

        [Test]
        public void NoParametersCorrectlyFormatted
        {
            string noParameters = TestClass.NoParameters();
            Assert.That(noParameters, Is.EqualTo("Method's Foo arguments >> No arguments.");
        }
    }</pre>
<p>Odpalamy testy, który oczywiście nie przechodzą. </p>
<p>Żeby testy zadziałały, nasza klasa <strong>LoggingHelpers</strong> wraz z metodą <strong>GetMethodParameters</strong> może wyglądać tak:</p>
<pre name="code"  class="c-sharp">
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;

public class LoggingHelpers
{
    public static string GetMethodParameters(params Func&lt;object&gt;[] expr)
    {
      // Pobieramy nazwę metody.
      string methodname = new StackFrame(1).GetMethod().Name;

      // wstępne formatowanie wynikowego napisu:
      string logmessage = "Method's " + methodname + " arguments >> ";

      // Tablica wyrażeń lambda jest pusta
      if (expr.Length == 0)
      {
        logmessage += "No arguments.";
      }
      else
      {
        try
        {
          // dla każdego Expression
          foreach (var par in expr)
          {
            // Zaawansowane sztuczki. Za pomocą MSIL znajdujemy informacje o Expression
            byte[] il = par.Method.GetMethodBody().GetILAsByteArray();

            // bajty 2-6 oznaczają uchwyt do naszych parametrów
            int fieldHandle = BitConverter.ToInt32(il, 2);

            // pobieramy FieldInfo tego parametru
            FieldInfo field = par.Target.GetType().Module.ResolveField(fieldHandle);

            // Formatujemy ostatecznie napis dla tego parametru.
            // Nazwę parametru uzyskujemy z FieldInfo, natomiast wartość wykonując przekazane Expression.
            logmessage += string.Format("{0}: {1}. ", field.Name, par() ?? "@null");
          }
        }
        catch
        {
        // Ignorujemy błędy - nic nie jest gorsze od doskonale działającej logiki aplikacji, która wywala się na narzędziach do logowania :-)
        // Tego typu try-catch to zła praktyka w aplikacji! W tym miejscu jest to stosowne, ale przestrzegam przed nadużywaniem "zjadania" wyjątków.

          logmessage += " FAILED reading arguments.";
        }
      }
    }
}</pre>
<p>Klasa do wykorzystania w aplikacji.</p>
<p>W kolejnej notce pokażę, jak to spiąć z log4net.</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/pobranie-parametrow-metody-w-c-wraz-z-wartosciami/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stack Overflow watch: najciekawsze wątki o .NET i C#</title>
		<link>http://xlab.pl/stack-overflow-watch-najciekawsze-watki-o-net-i-c/</link>
		<comments>http://xlab.pl/stack-overflow-watch-najciekawsze-watki-o-net-i-c/#comments</comments>
		<pubDate>Thu, 08 Oct 2009 10:00:35 +0000</pubDate>
		<dc:creator>Mateusz Kubiczek</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[interview questions]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[rozmowy o pracę]]></category>
		<category><![CDATA[Stack Overflow]]></category>

		<guid isPermaLink="false">http://www.xlab.pl/?p=547</guid>
		<description><![CDATA[Stack Overflow to portal do pytań i odpowiedzi na tematy programistyczne. Założycielami jest dwóch programistycznych guru i/lub celebrytów &#8211; Jeffa Atwooda i Joela Spolsky&#8217;ego. Atwood jest autorem bardzo popularnego i dosyć kontrowersyjnego bloga Coding Horror, jakiś czas temu nawet rzucił swoją główną pracę dla niego i dla Stack Overflow. Atwood dla mnie skończył się swego [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.stackoverflow.com">Stack Overflow</a> to portal do pytań i odpowiedzi na tematy programistyczne. Założycielami jest dwóch programistycznych guru i/lub celebrytów &#8211; Jeffa Atwooda i Joela Spolsky&#8217;ego.<br />
Atwood jest autorem bardzo popularnego i dosyć kontrowersyjnego bloga <a href="http://www.codinghorror.com/blog/">Coding Horror</a>, jakiś czas temu nawet rzucił swoją główną pracę dla niego i dla Stack Overflow. Atwood dla mnie skończył się swego czasu przy okazji <a href="http://www.codinghorror.com/blog/archives/001119.html">notek o PHP</a> &#8211; wyrzuciłem go z RSS-ów.<br />
Spolsky&#8217;ego natomiast nadal chętnie czytuję &#8211; od lat pisze on artykuły na <a href="http://www.joelonsoftware.com/">Joel on Software</a>.</p>
<p>Ich dzieło wspólne to właśnie Stack Overflow. System reputacji i nagród za zadawanie mądrych pytań i dawanie pomocnych odpowiedzi świetnie działa &#8211; moje trzy pytania na dosyć niszowe tematy prawie natychmiastowo miały odpowiedzi, za to trudno było znaleźć pytanie bez odpowiedzi.</p>
<p>Znalazłem tam masę zbiorów różnego rodzaju sztuczek programistycznych. Dzisiaj lista najciekawszych .NET-owych pytań. To także dosyć dobry materiał do przygotowywania się do testów podczas rekrutacji na wymarzone stanowisko programisty.</p>
<p><span id="more-547"></span></p>
<ul>
<li><a href="http://stackoverflow.com/questions/9033/hidden-features-of-c">&#8222;Ukryte&#8221; funkcje języka C#.</a> &#8211; Padają tam podstawowe rzeczy np. &#8222;yield&#8221; lub &#8222;using&#8221;, ale wiele z nich nie znałem, a teraz wykorzystuję samemu.</li>
<li> <a href="http://stackoverflow.com/questions/144833/most-useful-attributes-in-c"> Najbardziej przydatne atrybuty.</a> &#8211; Niestety mało kto używa atrybutów z frameworka, a co dopiero wykorzystuje własne w swoim kodzie. <em>System.Obsolete</em> to mój ulubiony ułatwiający refaktoryzację.</li>
<li> <a href="http://stackoverflow.com/questions/194484/whats-the-strangest-corner-case-youve-seen-in-c-or-net"> Najbardziej zadziwiające zachowania języka </a> &#8211; często spotykane na rozmowach kwalifikacyjnych. Nie cierpię pytań o tego typu szczegóły, ponieważ często ma się ona nijak do naszych umiejętności. Niemniej jednak lepiej zabłysnąć taką wiedzą, nawet jeżeli jej nigdy nie wykorzystamy.</li>
<li> <a href="http://stackoverflow.com/questions/271398/post-your-extension-goodies-for-c-net-codeplex-com-extensionoverflow"> Zbiór metod rozszerzających </a> &#8211; Wątek rewelacja. Mnóstwo świetnych metod rozszerzających, bardzo polecam. Autorzy nawet zrobili z tego gotową bibliotekę.</li>
<li> <a href="http://stackoverflow.com/questions/365489/questions-every-good-net-developer-should-be-able-to-answer"> Na jakie pytania każdy programista .NET powinien umieć odpowiedzieć? </a> &#8211; kolekcja pytań na rozmowy o pracę i do wykorzystania nacodzień.</li>
<li> <a href="http://stackoverflow.com/questions/380819/common-programming-mistakes-for-net-developers-to-avoid"> Częste pomyłki </a> &#8211; każdy programista .NET powinien się z tą listą zapoznać, często zdarza mi się widzieć kod, który podpada pod rzeczy wymienione w tym wątku.</li>
<li> <a href="http://stackoverflow.com/questions/662956/most-useful-free-net-libraries">Najbardziej przydatne darmowe biblioteki do .NET </a> &#8211; doskonały zbiór open source narzędzi. Używam wiele z nich &#8211; NHibernate, RhinoMocks, log4net, StructureMap, itd. Od nadmiaru wymienionych narzędzi może rozboleć głowa, ale każde jest opatrzone komentarzem, co ułatwia nam decyzję, czego użyć</li>
<li> <a href="http://stackoverflow.com/questions/541936/what-can-you-do-in-msil-that-you-cannot-do-in-c-or-vb-net"> Co możemy zrobić w MSIL, czego nie zrobimy w C#. </a> &#8211; bardziej zaawansowany temat wykorzystania samego MSIL (języka pośredniego, <em>assemblera</em> .NET) zamiast C#. Możemy sobie nawet zrobić przeładowane metody, które różnią się tylko typem zwracanym. Nawet nie wiem jak by to działało. :-)</li>
</ul>
<p>Polecam przeglądanie Stack Overflow samemu, baza wiedzy i pomocnych osób jest imponująca.</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/stack-overflow-watch-najciekawsze-watki-o-net-i-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>StructureMap: Wybieranie, który konstruktor ma zostać użyty</title>
		<link>http://xlab.pl/structuremap-wybieranie-ktory-konstruktor-ma-zostac-uzyty/</link>
		<comments>http://xlab.pl/structuremap-wybieranie-ktory-konstruktor-ma-zostac-uzyty/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 15:45:24 +0000</pubDate>
		<dc:creator>Mateusz Kubiczek</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[StructureMap]]></category>
		<category><![CDATA[wstrzykiwanie zależności]]></category>

		<guid isPermaLink="false">http://www.xlab.pl/?p=411</guid>
		<description><![CDATA[StructureMap to najstarszy framework dependency injection dla .NET. Jak łatwo się domyślić, używamy go w celu implementowania wstrzykiwania zależności (artykuł Martina Fowlera ). Pewien czas temu chciałem użyć go wraz z WCF. Dla webserwisu ServerService WCF wygenerował interfejs IServerServicePortType oraz klienta ServerServicePortTypeClient. Konfiguracja tego webserwisu znajdowała się w pliku Web.config. Zdefiniowałem regułę dla StructureMap: ObjectFactory.Configure( [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://structuremap.sourceforge.net/Default.htm">StructureMap</a> to najstarszy framework dependency injection dla .NET. Jak łatwo się domyślić, używamy go w celu implementowania <a href="http://pl.wikipedia.org/wiki/Wstrzykiwanie_zale%C5%BCno%C5%9Bci">wstrzykiwania zależności</a> (<a href="http://martinfowler.com/articles/injection.html">artykuł Martina Fowlera </a>).</p>
<p>Pewien czas temu chciałem użyć go wraz z WCF. Dla webserwisu ServerService WCF wygenerował interfejs <strong>IServerServicePortType</strong> oraz klienta <strong>ServerServicePortTypeClient</strong>. Konfiguracja tego webserwisu znajdowała się w pliku Web.config.</p>
<p>Zdefiniowałem regułę dla StructureMap:</p>
<pre class="c-sharp">ObjectFactory.Configure( x =&gt;
{
   x.ForRequestedType&lt;<em>IServerServicePortType</em>&gt;().TheDefault
     .Is.OfConcreteType&lt;ServerServicePortTypeClient&gt;();
});</pre>
<p>która powinna spowodować, że pobranie za pomocą <strong>ObjectFactory.GetInstance&lt;IServerServicePortType&gt;()</strong> zwróci nam obiekt klienta.</p>
<p>Wszystko fajnie, tylko że StructureMap wybierał zły konstruktor tej klasy. Jako że konfiguracja znajdowała się w pliku Web.config, chciałem, żeby StructureMap tworzył klasę za pomocą konstruktora bezparametrowego &#8211; niestety próbował użyć innego, co powodowało błąd (brak argumentów dla tego konstruktora). Spójrzmy na wygenerowane konstruktory klasy <strong>ServerServicePortTypeClient</strong>:</p>
<pre class="c-sharp">public ServerServicePortTypeClient();
public ServerServicePortTypeClient(string endpointConfigurationName);
public ServerServicePortTypeClient(string endpointConfigurationName, string remoteAddress);
public ServerServicePortTypeClient(string endpointConfigurationName,
                             System.ServiceModel.EndpointAddress remoteAddress);
public ServerServicePortTypeClient(System.ServiceModel.Channels.Binding binding);</pre>
<p>Wykorzystywany był drugi z argumentem <strong>endpointConfigurationName</strong>.</p>
<p>Nie tego oczekiwałem. Logiczne było, że zostanie wybrany konstruktor najlepiej pasujący do podanych argumentów &#8211; czyli brak argumentów spowoduje wybranie bezargumentowego. :-) Po pewnym czasie znalazłem rozwiązanie na <a href="http://codebetter.com/blogs/jeremy.miller/archive/2009/01/07/choosing-the-constructor-function-in-structuremap-without-attributes.aspx">blogu autora StructureMap.</a></p>
<pre class="c-sharp">ObjectFactory.Configure( x =&gt;
{
   x.SelectConstructor( () =&gt; new SoapPortTypeClient());
   x.ForRequestedType().TheDefault.Is.OfConcreteType();
});</pre>
<p>Pierwsze wyrażenie jest co najmniej ciekawe &#8211; nie tworzymy tutaj obiektu, tylko definiujemy lambdę, z której następne StructureMap odczyta, jakiego konstruktora powinien uzyć. Sprytne!</p>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/structuremap-wybieranie-ktory-konstruktor-ma-zostac-uzyty/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft PDC 2009</title>
		<link>http://xlab.pl/microsoft-pdc-2009/</link>
		<comments>http://xlab.pl/microsoft-pdc-2009/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 20:48:07 +0000</pubDate>
		<dc:creator>Mateusz Kubiczek</dc:creator>
				<category><![CDATA[Programowanie .NET]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[pdb08]]></category>
		<category><![CDATA[pdc09]]></category>

		<guid isPermaLink="false">http://www.xlab.pl/?p=352</guid>
		<description><![CDATA[Nie zdążyłem obejrzeć wszystkich interesujących mnie sesji z PDC2008, a tu Microsoft już zapowiedział PDC2009. No cóż, podobno lolcaty przełamują wszystkie lody, więc może to mi załatwi wejście. ;-) I can haz registration?]]></description>
			<content:encoded><![CDATA[<p>Nie zdążyłem obejrzeć wszystkich interesujących mnie <a href="http://channel9.msdn.com/pdc2008/">sesji</a> z PDC2008, a tu Microsoft już zapowiedział <a href="http://microsoftpdc.com/">PDC2009</a>. No cóż, podobno <a href="http://wyborcza.pl/1,99495,6855233,Przelam_lody_kotem.html">lolcaty przełamują wszystkie lody</a>, więc może to mi załatwi wejście. ;-)</p>
<dl id="attachment_353" class="wp-caption aligncenter" style="width: 394px;">
<dt class="wp-caption-dt"><img class="size-full wp-image-353" title="LolCatRenderer2.aspxtopDOESWANTbottomsize60imagenamecheeses" src="http://www.xlab.pl/wp-content/uploads/2009/08/LolCatRenderer2.aspxtopDOESWANTbottomsize60imagenamecheeses.jpg" alt="I can haz registration?" width="384" height="400" /></dt>
<dd class="wp-caption-dd">
<h2><a href="http://microsoftpdc.com/Registration">I can haz registration</a>?</h2>
</dd>
</dl>
]]></content:encoded>
			<wfw:commentRss>http://xlab.pl/microsoft-pdc-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

