<?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>blackfoot.pl</title>
	<atom:link href="http://blackfoot.pl/feed/" rel="self" type="application/rss+xml" />
	<link>http://blackfoot.pl</link>
	<description>... czyli Tomek Wójcik na tropie</description>
	<lastBuildDate>Sat, 21 May 2011 13:29:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Recenzja książki &#8222;The Art of Unit Testing: with Examples in .NET&#8221;</title>
		<link>http://blackfoot.pl/2011/05/recenzja-ksiazki-the-art-of-unit-testing-with-examples-in-net/</link>
		<comments>http://blackfoot.pl/2011/05/recenzja-ksiazki-the-art-of-unit-testing-with-examples-in-net/#comments</comments>
		<pubDate>Sat, 21 May 2011 13:03:41 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Recenzje książek]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[książki]]></category>
		<category><![CDATA[testowanie]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=206</guid>
		<description><![CDATA[Ostatnio wpadła mi w ręce książka The Art of Unit Testing: with Examples in .NET autorstwa Roy&#8217;a Osherove&#8217;a. Muszę przyznać, że mam nieco mieszane uczucia po jej przeczytaniu. Minusy: Książka liczy około 280 stron, ale czytając ją miałem wrażenie, że ta liczba jest mocno naciągnięta &#8211; olbrzymie marginesy, bardzo szeroka czcionka, dużo niezagospodarowanego miejsca itp. [...]]]></description>
			<content:encoded><![CDATA[<p style="float: left; margin-right: 5px;"><a href="http://www.amazon.com/gp/product/1933988274/ref=as_li_tf_il?ie=UTF8&#038;tag=blackfootpl-20&#038;linkCode=as2&#038;camp=217145&#038;creative=399349&#038;creativeASIN=1933988274" target="_blank"><img src="http://blackfoot.pl/blog/wp-content/uploads/2011/05/51VAZ9BwcvL._SL160_.jpg" border="0" alt="" /></a><img src="http://www.assoc-amazon.com/e/ir?t=blackfootpl-20&#038;l=as2&#038;o=1&#038;a=1933988274&#038;camp=217145&#038;creative=399349" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p>Ostatnio wpadła mi w ręce książka <a href="http://www.amazon.com/gp/product/1933988274/ref=as_li_tf_il?ie=UTF8&#038;tag=blackfootpl-20&#038;linkCode=as2&#038;camp=217145&#038;creative=399349&#038;creativeASIN=1933988274" target="_blank">The Art of Unit Testing: with Examples in .NET</a><img src="http://www.assoc-amazon.com/e/ir?t=blackfootpl-20&#038;l=as2&#038;o=1&#038;a=1933988274&#038;camp=217145&#038;creative=399349" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /> autorstwa <a title="Otwórz stronę" href="http://osherove.com/blog/" target="_blank">Roy&#8217;a Osherove&#8217;a</a>. Muszę przyznać, że mam nieco mieszane uczucia po jej przeczytaniu.</p>
<p><strong>Minusy:</strong><br />
Książka liczy około 280 stron, ale czytając ją miałem wrażenie, że ta liczba jest mocno naciągnięta &#8211; olbrzymie marginesy, bardzo szeroka czcionka, dużo niezagospodarowanego miejsca itp. Samym formatowaniem można by było zaoszczędzić przynajmniej kilkadziesiąt stron &#8211; ile drzew mogłoby wciąż rosnąć!</p>
<p>Pierwsze trzy rozdziały od biedy można polecić do przeczytania młodszym programistom &#8211; tym bardziej zaawansowanym wystarczy pobieżnie przerzucić te 140 stron wyłapując pojawiające się od czasu do czasu słowa-klucze.</p>
<p>W mojej opinii wybór <strong>Rhino Mocks</strong> też nie jest zbyt właściwy &#8211; może faktycznie jest on popularny, ale wydaje mi się, że zawdzięcza to temu, że jest chyba najdłużej na rynku. Niestety z tego samego powodu jego stosowanie jest bardzo uciążliwe. Dużo łatwiej jest mi wytłumaczyć pewne rzeczy juniorom na przykładzie młodszych i chyba przez to bardziej nowoczesnych frameworków.</p>
<p>Trochę bezsensowne moim zdaniem załączniki z długimi opisami różnych narzędzi &#8211; takie rzeczy szybko się dezaktualizują &#8211; dla mnie to kolejne 20 stron do &#8222;odciśnięcia&#8221;.
</p>
<p><strong>Plusy:</strong><br />
Pomimo tego, iż książka mówi o testowaniu, nie znajdziemy w niej nachalnej promocji TDD &#8211; są tam raptem 3 strony na ten temat, z których możemy dowiedzieć się jak TDD działa, jakie są plusy i minusy itp.</p>
<p>Autor wyjaśnia, co to znaczy pisać dobre testy jednostkowe (generalnie testy muszą być godne zaufania, łatwe w utrzymaniu oraz czytelne) oraz jak poznać te źle napisane. Z książki możemy dowiedzieć się również, że kod testów jest równie istotny, jak produkcyjny kod źródłowy. Opisane zostało także zarządzanie testami, wykorzystanie ciągłej integracji do automatycznego ich uruchamiania, ogromne znaczenie testów zwłaszcza podczas refaktoryzacji kodu itp.</p>
<p>Ostatnie rozdziały mówią o tym, jak wprowadzić pisanie testów do organizacji (autor porusza bardzo ciekawe tematy &#8211; np. jak radzić sobie z trudnymi ludźmi, jak stać się promotorem zmian, jak wybrać potencjalne miejsca, od których można zacząć itp.), a także jak pracować ze starym kodem.
</p>
<p><strong>Podsumowanie:</strong><br />
Widać, że autor ma olbrzymie doświadczenie i zna bardzo dobrze temat, o którym pisze. Jednak dla mnie ta książka powinna być przynajmniej o połowę cieńsza &#8211; jeżeli autor chciał mieć tyle stron, to powinien dodać kilka dodatkowych rozdziałów &#8211; np. rozwinąć myśl o wspomnianym tylko wykorzystaniu kontenerów IoC itp. Wydaje mi się, że warto tę książkę podsunąć do przeczytania młodszym programistom (oraz tym, którzy nie mieli do tej pory styczności z testami jednostkowymi) &#8211; dla nich ta książka będzie idealna. Dla tych, którzy już na co dzień piszą testy &#8211; dobrze jest ją przeczytać, aby uporządkować swoją wiedzę, ale wymienione wyżej minusy mogą w niektórych momentach spowodować lekką irytację podczas lektury.
</p>
<p>Z mieszanymi uczuciami, ale jednak <strong>polecam</strong> dla każdego programisty <strong>C#</strong>.<br />
<script type="text/javascript" src="http://www.assoc-amazon.com/s/link-enhancer?tag=blackfootpl-20&#038;o=1">
</script><br />
<noscript><br />
    <img src="http://www.assoc-amazon.com/s/noscript?tag=blackfootpl-20" alt="" /><br />
</noscript></p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/05/recenzja-ksiazki-the-art-of-unit-testing-with-examples-in-net/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[EN] WeakDelegate for all types of delegates</title>
		<link>http://blackfoot.pl/2011/03/en-weakdelegate-for-all-types-of-delegates/</link>
		<comments>http://blackfoot.pl/2011/03/en-weakdelegate-for-all-types-of-delegates/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 11:47:04 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=193</guid>
		<description><![CDATA[As I promised in I&#8217;m showing you corrected WeakDelegate&#60;TDelegate&#62; which is working with all types of delegates. The implementation was less challenging than I expected. Fortunately everything could be done with Expression Trees and usage of dynamic was not necessary. And now it&#8217;s time for some source code: public class WeakDelegate&#60;TDelegate&#62; where TDelegate : class [...]]]></description>
			<content:encoded><![CDATA[<p>As I promised in <a href="http://blackfoot.pl/2011/02/en-clr-via-c-3rd-edition-weakdelegate-logical-bug/">one of my previous posts</a> I&#8217;m showing you corrected <code>WeakDelegate&lt;TDelegate&gt;</code> which is working with all types of delegates. The implementation was less challenging than I expected. Fortunately everything could be done with <strong>Expression Trees</strong> and usage of <code>dynamic</code> was not necessary.<br />
And now it&#8217;s time for some source code:</p>
<pre class="brush: csharp; title: ;">
public class WeakDelegate&lt;TDelegate&gt;
	where TDelegate : class {
	private readonly WeakReference _weakTarget;
	private readonly TDelegate _proxyDelegate;
	private Action&lt;TDelegate&gt; _cleanUp;

	public WeakDelegate( TDelegate @delegate, Action&lt;TDelegate&gt; cleanUp ) {
		var d = @delegate as Delegate;

		if( d == null )
			throw new ArgumentNullException( &quot;delegate&quot; );

		if( d.Target == null || d.Method == null || d.Method.IsStatic )
			throw new ArgumentException(
				&quot;Can't create weak delegate to static method.&quot; );

		this._weakTarget = new WeakReference( d.Target );
		this._cleanUp = cleanUp;

		var targetType = d.Target.GetType();
		var returnType = d.Method.ReturnType;

		var lambdaArgs = d.Method.GetParameters()
			.Select( ( p, i ) =&gt;
				Expression.Parameter( p.ParameterType, &quot;a&quot; + i ) )
			.ToArray();

		var targetVar = Expression.Variable( targetType, &quot;target&quot; );

		var getTargetCall = Expression.Invoke( (Expression)
			this.GetType()
			.GetMethod( &quot;GetTargetBoundExpression&quot;,
				BindingFlags.Instance | BindingFlags.NonPublic )
			.MakeGenericMethod( targetType )
			.Invoke( this, new object[ 0 ] ) );

		var returnLabel = Expression.Label( returnType );
		var defaultReturn = Expression.Default( returnType );

		var lambda = Expression.Lambda&lt;TDelegate&gt;( Expression.Block(
			new[] { targetVar },
			new Expression[] {
				Expression.Assign( targetVar, getTargetCall ),
					Expression.IfThenElse(
						Expression.Equal( targetVar, Expression.Constant( null ) ),
						Expression.Return( returnLabel, defaultReturn ),
						Expression.Return( returnLabel,
							Expression.Call( targetVar, d.Method, lambdaArgs ) ) ),
					Expression.Label( returnLabel, defaultReturn )
				} ), lambdaArgs );

		this._proxyDelegate = lambda.Compile();
	}

	public static implicit operator TDelegate(
		WeakDelegate&lt;TDelegate&gt; weakDelegate ) {
		return weakDelegate != null ? weakDelegate._proxyDelegate : null;
	}

	private Expression GetTargetBoundExpression&lt;TTarget&gt;() {
		return (Expression&lt;Func&lt;TTarget&gt;&gt;) ( () =&gt; this.GetTarget&lt;TTarget&gt;() );
	}

	private TTarget GetTarget&lt;TTarget&gt;() {
		var target = (TTarget) this._weakTarget.Target;
		if( target != null )
			return target;

		if( this._cleanUp != null ) {
			this._cleanUp( this._proxyDelegate );
			this._cleanUp = null;
		}

		return target;
	}
}
</pre>
<p>In lines from 23 to 50 using types read from original delegate and expression trees I&#8217;m creating proxy <code>TDelegate</code> simmilar to the following metacode:</p>
<pre class="brush: csharp; title: ;">
this._proxyDelegate = (a0...aN) =&gt; {
	var target = this.GetTarget&lt;TTarget&gt;();
	if( target == null )
		return default( TDelegateReturnType );
	else
		return target.OriginalDelegateMethod( a0...aN );
}
</pre>
<p>The implementation is sill quite fast &#8211; only 6-9 times slower than direct delegate invocation. It has a lower performance than <code>WeakEventHandler&lt;TEventHandler&gt;</code> described in <a href="http://blackfoot.pl/2011/02/weakeventhandler-praktyczne-wykorzystanie-weakreference/">one of my previous posts</a> which is only 4-6 times slower.<br />
There are also few drawbacks of my solution:</p>
<ul>
<li>after the target is garbage collected, the proxy delegate will return default value of the <code>TDelegate</code>&#8216;s return type (I think that this can be solved somehow using for example <code>cleanUp</code> callback)</li>
<li>cleaning up is not thread safe etc.</li>
</ul>
<p>The source code with examples is <a href="http://cid-7e7a601e7f4fe768.office.live.com/self.aspx/BlackfootPL/20110306/WeakDelegate.cs" target="_blank" title="Download source code">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/03/en-weakdelegate-for-all-types-of-delegates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WeakEventHandler &#8211; praktyczne wykorzystanie WeakReference</title>
		<link>http://blackfoot.pl/2011/02/weakeventhandler-praktyczne-wykorzystanie-weakreference/</link>
		<comments>http://blackfoot.pl/2011/02/weakeventhandler-praktyczne-wykorzystanie-weakreference/#comments</comments>
		<pubDate>Sun, 27 Feb 2011 19:04:35 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=84</guid>
		<description><![CDATA[Trochę teoretycznego wstępu Środowisko .NET charakteryzuje się tym, że samo zarządza cyklem życia obiektów. Garbage collector potrafi wykryć, które obiekty nie są już potrzebne i usunąć je z pamięci. Oczywiście jest to bardzo duże uproszczenie całego mechanizmu &#8211; szczegóły jego działania są bardzo dobrze wyjaśnione w opisywanej przeze mnie wcześniej książce w rozdziale 21 &#8211; [...]]]></description>
			<content:encoded><![CDATA[<h3>Trochę teoretycznego wstępu</h3>
<p>Środowisko .NET charakteryzuje się tym, że samo zarządza cyklem życia obiektów. <em>Garbage collector</em> potrafi wykryć, które obiekty nie są już potrzebne i usunąć je z pamięci. Oczywiście jest to bardzo duże uproszczenie całego mechanizmu &#8211; szczegóły jego działania są bardzo dobrze wyjaśnione w opisywanej przeze mnie wcześniej książce <a href="http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/">&quot;CLR via C#, 3rd edition&quot;</a> w rozdziale 21 &#8211; <strong>Automatic Memory Management (Garbage Collection)</strong>.</p>
<p>Oprócz automatycznego zarządzania pamięcią <strong>CLR</strong> umożliwia także ręczne monitorowanie oraz kontrolę cyklu życia obiektów za pomocą <em>GC handle table</em>. Dodawanie oraz usuwanie wpisów do tej tabeli umożliwiają metody struktury <a title="Zobacz w MSDN" href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.aspx" target="_blank"><code>GCHandle</code></a>. Mechanizm ten jest szczególnie przydatny, kiedy komunikujemy się lub współpracujemy w jakiś sposób z kodem niezarządzalnym, ale część właściwości można także wykorzystać, gdy pracujemy tylko z kodem zarządzalnym &#8211; konkretnie chodzi mi tutaj o <em>słabe referencje</em>.</p>
<p>W dużej ogólności <strong>obiekt&nbsp;A</strong> musi posiadać referencję do <strong>obiektu&nbsp;B</strong>, aby mógł na nim wołać metody:<br/><br/><div id="attachment_98" class="wp-caption aligncenter" style="width: 335px"><img class="size-full wp-image-98" title="Diagram 1. Mocna referencja z obiektu A do obiektu B." src="/blog/wp-content/uploads/2011/02/WR01.png" alt="Diagram 1." width="325" height="55" /><p class="wp-caption-text">Diagram 1. Mocna referencja z obiektu A do obiektu B.</p></div><br/>Sytuacja taka uniemożliwia jednak automatyczne usunięcie <strong>obiektu&nbsp;B</strong> z pamięci, kiedy nie jest on już potrzebny, a jedyną referencją, jaka go jeszcze trzyma przy życiu, jest referencja posiadana przez <strong>obiekt&nbsp;A</strong>. Czasami takie zachowanie nie jest pożądane i aby temu zaradzić, możemy posłużyć się klasą <a title="Zobacz w MSDN" href="http://msdn.microsoft.com/en-us/library/system.weakreference.aspx" target="_blank"><code>WeakReference</code></a>, która opakowuje strukturę <a title="Zobacz w MSDN" href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.aspx" target="_blank"><code>GCHandle</code></a> umożliwiając łatwiejsze jej wykorzystanie w kodzie.</p>
<p>W praktyce wygląda to następująco. Zamiast takiego kodu:</p>
<pre class="brush: csharp; title: ;">
	class ClassB {
		public void Foo() { }
	}

	class ClassA
	{
		private ClassB _objectB;

		public ClassA( ClassB objectB ) {
			// mocna referencja z A do B
			_objectB = objectB;
		}

		public void CallB() {
			_objectB.Foo();
		}
	}
</pre>
<p>kod <strong>klasy A</strong> możemy napisać następująco z wykorzystaniem klasy <a title="Zobacz w MSDN" href="http://msdn.microsoft.com/en-us/library/system.weakreference.aspx" target="_blank"><code>WeakReference</code></a> i jej właściwości <a title="Zobacz w MSDN" href="http://msdn.microsoft.com/en-us/library/system.weakreference.target.aspx" target="_blank"><code>Target</code></a>:</p>
<pre class="brush: csharp; title: ;">
	class ClassA {
		private WeakReference _weakObjectB;

		public ClassA( ClassB objectB ) {
			// słaba referencja z A do B
			_weakObjectB = new WeakReference( objectB );
		}

		public void CallB() {
			// pobierz referencję do obiektu B
			var objectB = _weakObjectB.Target as ClassB;
			if( objectB != null ) { // jeżeli obiekt B jest jeszcze w pamięci
				objectB.Foo(); // to możemy zawołać na nim metodę Foo
			}
		}
	}
</pre>
</p>
<h3>I praktyczne zastosowanie</h3>
<p>Opisany powyżej mechanizm można w praktyczny sposób wykorzystać podczas pracy z <em>eventami</em>. Spójrzmy na uproszczony model:</p>
<pre class="brush: csharp; title: ;">
	class Producer {
		public event EventHandler&lt;EventArgs&gt; Event;

		public void Produce() {
			Console.WriteLine( &quot;Producer.Produce - raising event&quot; );
			if( this.Event != null ) {
				this.Event( this, EventArgs.Empty );
			}
		}
	}

	class Consumer {
		public Consumer( Producer producer ) {
			producer.Event += new EventHandler&lt;EventArgs&gt;( this.Consume );
		}

		private void Consume( object sender, EventArgs e ) {
			Console.WriteLine( &quot;Consumer.Consume - consuming event&quot; );
		}
	}

	static class SimpleWeakReferenceExample {
		public static void Run() {
			var producer = new Producer();
			var consumer = new Consumer( producer );

			producer.Produce();
			consumer = null; // konsument nie jest już nam potrzebny
			GC.Collect();
			// consumer i tak przeżyje,
			// ponieważ pośrednio referencję do niego trzyma consumer
			producer.Produce();
		}
	}
</pre>
<p>Obiekt klasy <code>Producer</code> jest producentem zdarzeń, na które zapisuje się obiekt klasy <code>Consumer</code>. Tworzy się nam taka oto struktura:<br/><br />
<div id="attachment_124" class="wp-caption aligncenter" style="width: 465px"><img src="/blog/wp-content/uploads/2011/02/WR02.png" alt="Diagram 2." title="Diagram 2. Diagram obiektów dla przykładu Producent-Konsument." width="455" height="205" class="size-full wp-image-124" /><p class="wp-caption-text">Diagram 2. Diagram obiektów dla przykładu Producent-Konsument.</p></div><br />
Pomimo tego, że konsument nie jest już potrzebny (linikja 28, czerwona strzałka na diagramie 2), to pośrednio poprzez <code>EventHandler</code> jest powiązany z producentem i będzie żył tak długo, jak i on. Aby temu zaradzić, można np. zaimplementować w klasie <code>Consumer</code> interfejs <code>IDisposable</code> i wołać metodę <code>Dispose</code>, w której konsument wypisuje się ze zdarzenia <code>Event</code> producenta. Niestety czasami w bardziej skomplikowanych przypadkach, nie jest to takie łatwe &#8211; kilkukrotnie spotkałem się z takimi sytuacjami. Pomóc może nam poprzednio opisany mechanizm <em>słabych referencji</em>.</p>
<h3>Błędny WeakEventHandler z książki <a href="http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/">&quot;CLR via C#, 3rd edition&quot;</a></h3>
<p>W książce <a href="http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/">&quot;CLR via C#, 3rd edition&quot;</a> znajduje się przykładowa implementacja klasy <code>WeakEventHandler</code> bazująca na bardziej ogólnej klasie <code>WeakDelegate&lt;TDelegate&gt;</code>, niestety posiada ona bardzo poważny błąd logiczny, którego &#8211; o dziwo &#8211; nikt do tej pory nie zgłosił. Problem opisałem w <a href="http://blackfoot.pl/2011/02/en-clr-via-c-3rd-edition-weakdelegate-logical-bug/">poprzednim wpisie</a> i zgłosiłem go do autora.</p>
<h3>Podstawowe założenia do implementacji WeakEventHandler&lt;TEventHandler&gt;</h3>
<p>Klasa ma umożliwiać tworzenie słabych <em>event handlerów</em> dla trzech typów delegatów:</p>
<ul>
<li>podstawowego, generycznego <code>EventHandler&lt;TEventArgs&gt;</code></li>
<li>niegenerycznego <code>EventHandler</code></li>
<li>dowolnego delegata, którego sygnatura jest zgodna z jednym z dwóch powyższych (ten scenariusz dodałem po dyskusji z Jeffrey&#8217;iem Richterem &#8211; ma zapewnić wsparcie dla starszego typu <em>eventów</em> obecnych w dużych ilościach zwłaszcza w <em>WinForms</em>)</li>
</ul>
<p>Nasza struktura obiektów będzie wyglądać następująco:<br/><br />
<div id="attachment_162" class="wp-caption aligncenter" style="width: 465px"><img src="/blog/wp-content/uploads/2011/02/WR03.png" alt="Diagram 3." title="Diagram 3. Wymagane połączenia obiektów." width="455" height="245" class="size-full wp-image-162" /><p class="wp-caption-text">Diagram 3. Wymagane połączenia obiektów.</p></div><br />
Przerywaną linią jest zaznaczona słaba referencja. Musimy także zająć się mocną referencją od <strong>producenta</strong> do naszego niebieskiego delegata &#8211; po usunięciu <strong>konsumenta</strong>, kiedy delegat już nie jest potrzeby, powinien sam wyrejestrować się ze zdarzenia.</p>
<h3>Implementacja WeakEventHandler&lt;TEventHandler&gt;</h3>
<p>Sporo eksperymentowałem z różnymi implementacjami, aż w końcu doszedłem do czegoś takiego:</p>
<pre class="brush: csharp; title: ;">
public sealed class WeakEventHandler&lt;TEventHandler&gt;
	where TEventHandler : class
{
	private delegate void OpenEventHandler&lt;TTarget, TEventArgs&gt;
		( TTarget target, object sender, TEventArgs eventArgs )
		where TTarget : class
		where TEventArgs : EventArgs;

	private readonly WeakReference _weakTarget;
	private readonly Delegate _openEventHandler;
	private readonly Action&lt;TEventHandler&gt; _cleanUp;
	private readonly TEventHandler _proxyHandler;

	public WeakEventHandler(
		TEventHandler eventHandler, Action&lt;TEventHandler&gt; cleanUp ) {
		var d = eventHandler as Delegate;
		if( d == null || d.Target == null )
			throw new ArgumentException(
				&quot;Can't make weak event handler to static method.&quot;, &quot;d&quot; );

		if( cleanUp == null )
			throw new ArgumentNullException( &quot;cleanUp&quot; );

		// store event handler target as a WeakReference
		_weakTarget = new WeakReference( d.Target );
		_cleanUp = cleanUp;

		// extract the types from the event handler
		var eventHandlerType = typeof( TEventHandler );
		var targetType = d.Target.GetType();
		var eventArgsType = eventHandlerType.IsGenericType
			? eventHandlerType.GetGenericArguments()[ 0 ]
			: eventHandlerType.GetMethod( &quot;Invoke&quot; )
				.GetParameters()[ 1 ].ParameterType;

		// create open event handler for fast calling of the real event handler
		Type openEventHandlerType = typeof( OpenEventHandler&lt;,&gt; )
			.MakeGenericType( eventHandlerType, targetType, eventArgsType );
		_openEventHandler = Delegate.CreateDelegate(
			openEventHandlerType, null, d.Method );

		// create proxy handler that points to our proxy method
		var proxyHandlerMethod =
			typeof( WeakEventHandler&lt;TEventHandler&gt; )
			.GetMethod(
				&quot;ProxyHandler&quot;,
				BindingFlags.Instance | BindingFlags.NonPublic )
			.MakeGenericMethod( targetType, eventArgsType );
		_proxyHandler =
			Delegate.CreateDelegate( eventHandlerType, this, proxyHandlerMethod )
			as TEventHandler;
	}

	private void ProxyHandler&lt;TTarget, TEventArgs&gt;(
		object sender, TEventArgs e )
		where TTarget : class
		where TEventArgs : EventArgs
	{
		var target = _weakTarget.Target as TTarget;
		var openEventHandler = this._openEventHandler
			as OpenEventHandler&lt;TTarget, TEventArgs&gt;;

		// if target is still alive
		if( target != null || openEventHandler == null )
			openEventHandler( target, sender, e ); // call it
		else
			_cleanUp( _proxyHandler ); // else clean up
	}

	public static implicit operator TEventHandler(
		WeakEventHandler&lt;TEventHandler&gt; weakEventHandler ) {
		return weakEventHandler != null
			? weakEventHandler._proxyHandler
			: null;
	}
}
</pre>
<p>Implementacja spełnia postawione wcześniej założenia, co ważne &#8211; jest relatywnie szybka &#8211; około 4-6 razy wolniejsza, niż bezpośrednie wywołanie delegata. Musimy także podać delegat <code>cleanUp</code>, który umożliwi wyrejestrowanie się ze zdarzenia i posprzątanie, kiedy <code>_target</code> zostanie już usunięty. Wszystkie niezbędne dane są wydobywane z oryginalnego <code>eventHandler</code>a, następnie tworzone są: tzw. <em>open event handler</em> &#8211; delegat, który umożliwia późniejsze szybkie wołanie metody na konsumencie oraz <em>proxy event handler</em> &#8211; delegat, który wskazuje na generyczną metodę <code>ProxyHandler</code>.</p>
<h3>Rozszerzenia</h3>
<p>Aby ułatwić używanie ww. implementacji, można skorzystać z dodatkowych <em>extension methods</em>:</p>
<pre class="brush: csharp; title: ;">
public static class WeakEventHandlerExtensions {
	// usage:
	// p.SomeEvent += new SomeEventHandler( c.HandleEvent )
	//                 .AsWeak( eh =&gt; p.SomeEvent -= c.HandleEvent );
	public static TEventHandler AsWeak&lt;TEventHandler&gt;(
		this TEventHandler eventHandler, Action&lt;TEventHandler&gt; cleanUp )
		where TEventHandler : class {
		return new WeakEventHandler&lt;TEventHandler&gt;( eventHandler, cleanUp );
	}

	// usage:
	// p.SomeEvent += new EventHandler( c.HandleEvent )
	//                 .AsWeak( eh =&gt; p.SomeEvent -= c.HandleEvent );
	public static EventHandler AsWeak(
		this EventHandler eventHandler, Action&lt;EventHandler&gt; cleanUp ) {
		return new WeakEventHandler&lt;EventHandler&gt;( eventHandler, cleanUp );
	}

	// usage:
	// p.SomeEvent += new EventHandler&lt;SomeEventArgs&gt;( c.HandleEvent )
	//                 .AsWeak( eh =&gt; p.SomeEvent -= c.HandleEvent );
	public static EventHandler&lt;TEventArgs&gt; AsWeak&lt;TEventArgs&gt;(
		this EventHandler&lt;TEventArgs&gt; eventHandler,
		Action&lt;EventHandler&lt;TEventArgs&gt;&gt; cleanUp )
		where TEventArgs : EventArgs {
		return new WeakEventHandler&lt;EventHandler&lt;TEventArgs&gt;&gt;(
			eventHandler, cleanUp );
	}
}
</pre>
</p>
<h3>Użycie</h3>
<p>
<pre class="brush: csharp; title: ;">
// decision on event consumer side:
producer.Event += new EventHandler( this.HandleEvent )
	.AsWeak( eh =&gt; producer.Event -= eh );

// decision on event producer side
// caution, with this construction it's not possible
// to deregister from the event
public class EventProvider {
	private EventHandler&lt;EventArgs&gt; _event;
	public event EventHandler&lt;EventArgs&gt; Event {
		add {
			this._event += value.AsWeak( eh =&gt; this._event -= eh );
		}
		remove {
			this._event -= value;
		}
	}

	public void Raise() {
		this._event( this, EventArgs.Empty );
	}
}
</pre>
<p>Jak widać z załączonych przykładów, użycie klasy <code>WeakEventHandler</code> poprzez <em>extension methods</em> <code>AsWeak</code> jest bardzo proste. Ciekawostką jest możliwość wykorzystania rozszerzeń także po stronie producenta i stworzenie słabego <em>eventa</em> &#8211; Jeffrey Richter dostrzegł w tym kodzie błąd &#8211; a mianowicie nie jest możliwe wyrejestrowanie <strong>konsument</strong> z <em>eventa</em>. Aby tego dokonać, należałoby zmienić lekko implementację części <code>remove</code> oraz dodać metody pozwalające na porównanie obiektów <code>WeakEventHandler&lt;TEventHandler&lt;</code> z obiektami <code>TEventHandler</code>.
</p>
<p>Implementację klasy wraz z rozszerzeniami oraz opisywanymi przykładami można pobrać <a href="http://cid-7e7a601e7f4fe768.office.live.com/self.aspx/BlackfootPL/20110227/WeakEventHandler.cs" target="_blank" title="Pobierz kod źródłowy">tutaj</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/02/weakeventhandler-praktyczne-wykorzystanie-weakreference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[EN] &#8222;CLR via C#, 3rd edition&#8221; &#8211; WeakDelegate logical bug</title>
		<link>http://blackfoot.pl/2011/02/en-clr-via-c-3rd-edition-weakdelegate-logical-bug/</link>
		<comments>http://blackfoot.pl/2011/02/en-clr-via-c-3rd-edition-weakdelegate-logical-bug/#comments</comments>
		<pubDate>Sat, 26 Feb 2011 14:33:16 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[.NET]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=131</guid>
		<description><![CDATA[While reading the excellent book of Jeffrey Richter &#8211; I&#8217;ve found quite a serious problem in one of the examples. Class WeakDelegate&#60;TDelegate&#62; (on page 562) has a logical bug and it simply will not work as expected. I&#8217;ve searched the errata and I&#8217;m surprised that nobody has yet noticed that. The problem that Jeffry wanted [...]]]></description>
			<content:encoded><![CDATA[<p>While reading the excellent book of <a title="Open blog" href="http://www.wintellect.com/cs/blogs/jeffreyr/default.aspx" target="_blank">Jeffrey Richter</a> &#8211; <a href="http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/">&quot;CLR via C#, 3rd edition&quot;</a> I&#8217;ve found quite a serious problem in one of the examples. Class <code>WeakDelegate&lt;TDelegate&gt;</code> (on page 562) has a logical bug and it simply will not work as expected. I&#8217;ve searched the <a href="http://oreilly.com/catalog/errata.csp?isbn=9780735627048" target="_blank">errata</a> and I&#8217;m surprised that nobody has yet noticed that.</p>
<p>The problem that Jeffry wanted to solve is as follows: the reference from the event producer to the event consumer should be weak, so in the case when the event consumer object has no other reason to live, it can be garbage collected. Jeffrey was trying to find a general solution for that and developed the abstract class <code>WeakDelegate&lt;TDelegate&gt;</code> that is holding a <em>weak reference</em> to the original delegate (I&#8217;ve removed some unnecessary code to make it clear):</p>
<pre class="brush: csharp; title: ;">
	public abstract class WeakDelegate&lt;TDelegate&gt;
		where TDelegate : class /* MulticastDelegate */ {
		private WeakReference&lt;TDelegate&gt; m_weakDelegate;

		public WeakDelegate( TDelegate @delegate ) {
			var md = (MulticastDelegate) (Object) @delegate;
			if( md.Target == null )
				throw new ArgumentException(
					&quot;Can't do a WeakDelegate to a static method.&quot; );

			// Save a WeakReference to the delegate
			m_weakDelegate = new WeakReference&lt;TDelegate&gt;( @delegate );
		}

		protected TDelegate GetRealDelegate() {
			// If the real delegate hasn't been GC'd yet, just return it
			TDelegate realDelegate = m_weakDelegate.Target;
			if( realDelegate != null ) return realDelegate;

			// The real delegate was GC'd,
			// we don't need our WeakReference to it anymore (it can be GC'd)
			m_weakDelegate.Dispose();
			return null;   // The real delegate was GC'd and can't be called
		}

		// All derived classes must return a delegate
		// to a private method matching the TDelegate type
		public abstract TDelegate GetDelegate();

		// Implicit conversion operator to convert
		// a WeakDelegate object to an actual delegate
		public static implicit operator TDelegate(
			WeakDelegate&lt;TDelegate&gt; @delegate ) {
			return @delegate.GetDelegate();
		}
	}

	// This class provides support
	// for the generic EventHandler&lt;TEventArgs&gt; delegate
	public sealed class WeakEventHandler&lt;TEventArgs&gt;
		: WeakDelegate&lt;EventHandler&lt;TEventArgs&gt;&gt;
		where TEventArgs : EventArgs {
		public WeakEventHandler( EventHandler&lt;TEventArgs&gt; @delegate )
			: base( @delegate ) { }

		public override EventHandler&lt;TEventArgs&gt; GetDelegate() {
			return Callback; }

		private void Callback( Object sender, TEventArgs e ) {
			// If the target hasn't been GC'd invoke it
			var eh = base.GetRealDelegate();
			if( eh != null ) eh( sender, e );
		}
	}
</pre>
</p>
<p>So our object diagram looks like below &#8211; can you spot the problem?<br/><br />
<div id="attachment_137" class="wp-caption aligncenter" style="width: 465px"><img src="/blog/wp-content/uploads/2011/02/CLR01.png" alt="1. Object diagram." title="1. Object diagram." width="455" height="245" class="size-full wp-image-137" /><p class="wp-caption-text">Object diagram</p></div><br />
Suppose that our <strong>consumer</strong> is still necessary and somehow we are holding a reference to it in our application. What will happen during the first garbage collection? The answer is &#8211; <strong>the original delegate will be garbage collected</strong> because nothing is holding a reference to it (except the <code>WeakDelegate</code> but that reference is weak) and our consumer will stop receiving the events from the <strong>producer</strong>.<br/><br />
<div id="attachment_141" class="wp-caption aligncenter" style="width: 465px"><img src="/blog/wp-content/uploads/2011/02/CLR02.png" alt="" title="2. Object diagram after first garbage collection" width="455" height="245" class="size-full wp-image-141" /><p class="wp-caption-text">2. Object diagram after first garbage collection</p></div><br />
The example from book (page 561) is working only because it is a very special case that will not work in reality &#8211; during the first garbage collection both the <strong>original delegate</strong> and the <strong>consumer</strong> (<code>DoNotLiveJustForTheEvent</code> object) are collected.</p>
<p>
To solve our problem we need something like this:<br/><br />
<div id="attachment_143" class="wp-caption aligncenter" style="width: 465px"><img src="/blog/wp-content/uploads/2011/02/CLR04.png" alt="" title="3. Object diagram with required references" width="455" height="245" class="size-full wp-image-143" /><p class="wp-caption-text">3. Object diagram with required references</p></div><br />
The <strong>original delegate</strong> is necessary only to extract the target and method from it and use that knowledge to build weak event handler. My solution is explained in <a href="http://blackfoot.pl/2011/02/weakeventhandler-praktyczne-wykorzystanie-weakreference/">my other post</a> (it&#8217;s written in Polish but code examples and the diagrams are quite easy to understand). The source code with examples is <a href="http://cid-7e7a601e7f4fe768.office.live.com/self.aspx/BlackfootPL/20110227/WeakEventHandler.cs" target="_blank" title="Download source code">here</a>. It&#8217;s not a general solution &#8211; I&#8217;ve developed <code>WeakEventHandler&lt;TEventHandler&gt;</code> that is working only with non-generic <code>EventHandler</code>, generic <code>EventHandler&lt;TEventArgs&gt;</code> and custom delegates with signature identical to previous two, but the implementation is quite fast (4-6 times slower than direct delegate invocation). The general solution (that will handle all types of the delegates) is also possible &#8211; I will try to show it sometime in the future &#8211; I&#8217;m thinking about building handlers in runtime using Expressions and using <code>dynamic</code> keyword to invoke open event handlers (but it can be slow).</p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/02/en-clr-via-c-3rd-edition-weakdelegate-logical-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recenzja książki &#8222;CLR via C#, 3rd edition&#8221;</title>
		<link>http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/</link>
		<comments>http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/#comments</comments>
		<pubDate>Sat, 19 Feb 2011 21:32:59 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Recenzje książek]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[książki]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=59</guid>
		<description><![CDATA[Kilka lat temu Krzysztof Koźmic polecił mi do przeczytania drugie wydanie książki CLR via C# napisanej przez Jeffrey&#8217;a Richtera. Pamiętam, że zrobiłem to wtedy z wielką przyjemnością. Książka dotyczyła CLR w wersji 2.0, w międzyczasie pojawił się CLR w wersji 4.0, więc z niecierpliwością czekałem na kolejną jej edycję, która ukazała się nareszcie na początku 2010 [...]]]></description>
			<content:encoded><![CDATA[<p style="float: left; margin-right: 5px;"><a href="http://www.amazon.com/gp/product/0735627045?ie=UTF8&amp;tag=blackfootpl-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0735627045" target="_blank"><img src="http://blackfoot.pl/blog/wp-content/uploads/2011/02/412wa7iEt3L._SL160_.jpg" border="0" alt="" /></a><img style="border: none !important; margin: 0px !important;" src="http://www.assoc-amazon.com/e/ir?t=blackfootpl-20&amp;l=as2&amp;o=1&amp;a=0735627045" border="0" alt="" width="1" height="1" /></p>
<p>Kilka lat temu <a title="Otwórz stronę" href="http://kozmic.pl" target="_blank">Krzysztof Koźmic</a> polecił mi do przeczytania drugie wydanie książki <a href="http://www.amazon.com/gp/product/0735627045?ie=UTF8&amp;tag=blackfootpl-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0735627045">CLR via C#</a><img style="border: none !important; margin: 0px !important;" src="http://www.assoc-amazon.com/e/ir?t=blackfootpl-20&amp;l=as2&amp;o=1&amp;a=0735627045" border="0" alt="" width="1" height="1" /> napisanej przez <a title="Otwórz stronę" href="http://www.wintellect.com/cs/blogs/jeffreyr/default.aspx" target="_blank">Jeffrey&#8217;a Richtera</a>. Pamiętam, że zrobiłem to wtedy z wielką przyjemnością. Książka dotyczyła <strong>CLR</strong> w wersji <strong>2.0</strong>, w międzyczasie pojawił się <strong>CLR</strong> w wersji <strong>4.0</strong>, więc z niecierpliwością czekałem na kolejną jej edycję, która ukazała się nareszcie na początku 2010 roku.</p>
<p>Do tej pory przeczytałem ją już dwa razy od deski do deski i dodatkowo dosyć często wracam do niektórych rozdziałów odkrywając coraz to nowe szczegóły i ciekawostki. Mogę zdecydowanie stwierdzić, że jest to jedna z najlepszych spośród przeczytanych przeze mnie książek dotyczących <strong>.NET</strong>. Uważam ją za obowiązkową lekturę dla każdego, kto chce być poważnym i świadomym programistą <strong>C#</strong>, a nie jakimś tam zwykłym kodoklepaczem znającym jedynie składnię języka. Dzięki niej można dowiedzieć się, co tak naprawdę dzieje się pod spodem, jak są w praktyce realizowane przez środowisko <strong>.NET</strong> pewne koncepcje oraz dlaczego są one realizowane tak, a nie inaczej.</p>
<p>Autor w prosty i bardzo przystępny sposób za pomocą wielu praktycznych przykładów potrafi wyjaśnić nawet skomplikowane idee i problemy. Powszechnie książkę tę uważa się za przeznaczoną dla zaawansowanych programistów, ale ja osobiście nie podzielam tych opinii. Owszem &#8211; jeżeli ktoś już posiada mocne podstawy, to jest w stanie wydobyć z niej dużo więcej niż początkujący programista, jednakże każdy może w niej znaleźć coś odpowiedniego dla siebie i swojego poziomu wiedzy. Nie jest to książka do jednorazowego, szybkiego przeczytania &#8211; raczej powinna ona być cały czas do naszej dyspozycji gdzieś tam na półce.</p>
<p><strong>Zdecydowanie polecam</strong> dla każdego programisty <strong>C#</strong>.<br />
<script type="text/javascript" src="http://www.assoc-amazon.com/s/link-enhancer?tag=blackfootpl-20&#038;o=1">
</script><br />
<noscript><br />
    <img src="http://www.assoc-amazon.com/s/noscript?tag=blackfootpl-20" alt="" /><br />
</noscript></p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/02/recenzja-ksiazki-clr-via-c-3rd-edition/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jak założyć blog w kilku &#8216;prostych&#8217; krokach</title>
		<link>http://blackfoot.pl/2011/02/jak-zalozyc-blog-w-kilku-prostych-krokach/</link>
		<comments>http://blackfoot.pl/2011/02/jak-zalozyc-blog-w-kilku-prostych-krokach/#comments</comments>
		<pubDate>Sat, 19 Feb 2011 12:36:45 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=37</guid>
		<description><![CDATA[Po podjęciu decyzji o założeniu blogu musiałem rozwiązać kilka kwestii technicznych. Miejsce Ponieważ do dyspozycji miałem swoją domenę oraz miejsce na serwerze i chciałem je wykorzystać, nie szukałem serwisów umożliwiających założenie i prowadzenie blogu. Dla tych, którzy nie mają takiej możliwości, zapytanie w dowolnej wyszukiwarce zwróci wiele popularnych i darmowych systemów blogowych. Dla mnie osobiście [...]]]></description>
			<content:encoded><![CDATA[<p>Po podjęciu decyzji o założeniu blogu musiałem rozwiązać kilka kwestii technicznych.</p>
<h3>Miejsce</h3>
<p>Ponieważ do dyspozycji miałem swoją domenę oraz miejsce na serwerze i chciałem je wykorzystać, nie szukałem serwisów umożliwiających założenie i prowadzenie blogu. Dla tych, którzy nie mają takiej możliwości, zapytanie w dowolnej wyszukiwarce zwróci wiele popularnych i darmowych systemów blogowych. Dla mnie osobiście jedną z najważniejszych zalet posiadania własnego serwisu jest możliwość dowolnego modyfikowania plików źródłowych i eksperymentowania ze skryptami, wtyczkami itp.</p>
<h3>Platforma</h3>
<p>Po moich niedługich poszukiwaniach na zdecydowanego lidera wśród darmowych systemów do blogowania wyrósł <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a>. Jest wolny i darmowy, ilość motywów oraz wtyczek jest ogromna, bardzo dużo osób go używa, więc nie ma problemu ze znalezieniem rozwiązań różnych problemów, no i posiada bardzo rozbudowany system pomocy dla kogoś lubiącego poszperać sobie trochę w kodzie PHP.</p>
<p>Przed instalacją na serwerze docelowym, dobrze jest pobawić się wcześniej systemem w domu. Samodzielna instalacja wymaganego do tego oprogramowania może i nie jest zbyt skomplikowana, ale na pewno zajmuje trochę czasu. Lepiej w tym celu wykorzystać jeden z gotowych pakietów <a title="Otwórz opis na Wikipedii" href="http://pl.wikipedia.org/wiki/WAMP" target="_blank">WAMP</a> (lub <a title="Otwórz opis na Wikipedii" href="http://pl.wikipedia.org/wiki/LAMP" target="_blank">LAMP</a>) &#8211; ja wybrałem <a title="Otwórz stronę" href="http://www.easyphp.org/" target="_blank">EasyPHP</a>, ponieważ posiada coś takiego jak <em>moduły</em>, czyli zestawy wstępnie skonfigurowanych, najpopularniejszych aplikacji webowych, m. in. aplikację <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a>.</p>
<h3>Motyw</h3>
<p>Domyślny motyw dostarczany z <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a> nie jest szczególnie ładny, więc pierwszą rzeczą, którą chce się zrobić po instalacji, jest zmiana wyglądu. Po wybraniu <em>Wygląd -&gt; Zainstaluj motywy</em> z panelu administracyjnego, mamy możliwość wyszukiwania skórek. Tutaj zaczęły się dla mnie pierwsze schody &#8211; paradoksalnie im więcej mam do wyboru, tym trudniej jest mi coś wybrać. Zasadniczo wiedziałem czego szukam &#8211; czegoś jasnego, wesołego i zielonego <img src='http://blackfoot.pl/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Po przeglądnięciu setek i przetestowaniu kilkudziesięciu motywów zniechęcony zdecydowałem, że chyba łatwiej będzie zrobić własną skórkę &#8211; i tutaj mogę powiedzieć, że to był błąd. Wstępny projekt i rozplanowanie strony zrobiłem bardzo szybko, wgryzłem się mocno w dokumentację <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a>, wszystko zaczęło działać, jak chciałem, ale na tymczasowych elementach, więc zabrałem się za wygląd.</p>
<p>Miałem kilkuletnią przerwę w stosowaniu technologii webowych, nie wspominałem ich najlepiej, ale pomyślałem &#8211; mamy przecież <strong>CSS3</strong>, <strong>HTML5</strong> itp., strony powstają na potęgę, na pewno ludzie definiujący te standardy po tylu latach wymyślili, jak ułatwić pracę programistom. Ale okazało się, że było to dla nich za trudne &#8211; prosta rzecz, jak np. pozycjonowanie elementów (centrowanie w poziomie lub pionie) bez stosowania magicznych sztuczek, wciąż nie jest możliwa, uzyskanie sensownego ułożenia sekcji za pomocą jedynych, boskich elementów <code>div</code> też jest problematyczne. Na takie przeszkody napotykałem nieustannie i posuwałem się do przodu bardzo powoli. Możliwe, że to kwestia braku wiedzy i doświadczenia, ale mimo wszystko na tle np. <strong>WPF</strong> czy <strong>Silverlight</strong> wypadło to bardzo blado.</p>
<p>Jeszcze raz przejrzałem istniejące motywy i zdecydowałem się na <a title="Otwórz stronę motywu" href="http://mythem.es/my/world-with-grass-and-dew" target="_blank">my theme with grass and dew</a>, ale okazało się, że nie posiada ona polskiej wersji językowej, a wszystkie teksty angielskie są &#8211; jak to się tak ładnie mówi &#8211; <em>zahardkodowane</em>, więc musiałem przetłumaczyć je na polskie przeszukując wszystkie pliki <em>php</em>. Przy okazji zwiększyłem szerokość motywu i delikatnie dostosowałem style <strong>CSS</strong>. Problem prawdopodobnie pojawi się podczas aktualizacji motywu.</p>
<h3>Wtyczki</h3>
<p>Z wtyczkami eksperymentowałem przez pół dnia, na prawdę jest ich bardzo dużo. Na razie wybrałem następujące:</p>
<ul>
<li><strong>Maintenance Mode</strong> &#8211; umożliwia włączenie trybu <em>maintenance, </em>w którym artykuły są dostępne tylko dla zalogowanych użytkowników, dla reszty świata widoczna jest informacja o trwającej nad stroną pracy. Sama wtyczka również nie posiada polskiego tłumaczenia, ale jego dodanie jest już dużo łatwiejsze, gdyż wykorzystano w niej system tłumaczeń stosowany w <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a>. Dodatkowo stworzyłem swoją własną stronę <strong>503</strong> i dodałem ją do motywu &#8211; jest ona wyświetlana w trakcie trybu utrzymaniowego.</li>
<li><strong>WP-PageNavi</strong> &#8211; wtyczka ułatwiająca nawigację po artykułach na blogu. Zamiast enigmatycznych odnośników <em>&#8222;starsze-nowsze artykuły&#8221; </em>wyświetlana jest ilość stron, bieżąca strona itp. Tutaj również trzeba było zaktualizować style <strong>CSS</strong> oraz ponownie zmodyfikować szablony motywu.</li>
<li><strong>SyntaxHighlighter Evolved</strong> &#8211; jedna z wielu przetestowanych przeze mnie wtyczek służących do osadzania kodu źródłowego w artykułach. Zaleta &#8211; posiada wsparcie dla <strong>F#</strong>, mam nadzieję, że jej działanie będzie można zobaczyć już w następnych wpisach.</li>
<li><strong>Sociable Polska Edycja</strong> &#8211; dzielenie się odnośnikami do artykułów to już praktycznie standard. Wtyczka posiada tę zaletę, że obsługuje polskie serwisy. Dodałem tylko obsługę <a title="Otwórz odnośnik" href="http://develway.pl" target="_blank">develway.pl</a> oraz <a title="Otwórz odnośnik" href="http://dotnetomaniak.pl" target="_blank">dotnetomaniak.pl</a> (zgłosiłem już do autora prośbę, aby je dodać w następnej wersji wtyczki) oraz zmodyfikowałem (a w zasadzie lekko doprecyzowałem) style <strong>CSS</strong>, ponieważ miałem konflikty ze stylami motywu.</li>
<li><strong>PHP Code Widget</strong> &#8211; domyślnie w <a title="Otwórz polską stronę WordPress" href="http://pl.wordpress.org/" target="_blank">WordPress</a> jest <em>widżet</em>, który umożliwia osadzenie w bocznym menu dowolnego tekstu oraz kodu <strong>HTML</strong>,<strong> </strong>nie pozwala on jednak wstawić kodu <strong>PHP</strong>, a właśnie to umożliwia ta wtyczka.</li>
<li><strong>Contact Form 7</strong> &#8211; umożliwia tworzenie formularzy w bardzo prosty sposób &#8211; ja wykorzystałem ją do zrobienia <a href="http://blackfoot.pl/kontakt/">formularza kontaktowego</a>.</li>
<li><strong>CF Internal Link Shortcode</strong> &#8211; umożliwia łatwe tworzenie odnośników do wewnętrznych stron lub artykułów.</li>
</ul>
<p>Podejrzewam, że wiele innych odkryję jeszcze po drodze.</p>
<h3>Podsumowanie</h3>
<p>Prace nad postawieniem strony trwały cały weekend, podczas których nauczyłem się wielu ciekawych rzeczy. Głównymi problemami, z jakimi się trzeba zmierzyć podczas samodzielnej instalacji, to brak tłumaczeń wielu tematów i wtyczek oraz brak wsparcia dla polskich serwisów w wielu wtyczkach. Dla kogoś, kto nie czuje się swobodnie w kodzie <strong>PHP</strong> lub nie ma czasu na takie zabawy, zdecydowanie łatwiejsze będzie założenie sobie bloga w jednym z istniejących serwisów.</p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/02/jak-zalozyc-blog-w-kilku-prostych-krokach/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Przygodę czas zacząć&#8230;</title>
		<link>http://blackfoot.pl/2011/02/przygode-czas-zaczac/</link>
		<comments>http://blackfoot.pl/2011/02/przygode-czas-zaczac/#comments</comments>
		<pubDate>Sun, 13 Feb 2011 21:13:25 +0000</pubDate>
		<dc:creator>Tomasz Wójcik</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[blog]]></category>

		<guid isPermaLink="false">http://blackfoot.pl/?p=32</guid>
		<description><![CDATA[No to stało się, założyłem sobie blog. Od dłuższego czasu brakowało mi miejsca, w którym mógłbym gromadzić swoje notatki, przemyślenia, recenzje książek, odnośniki do prezentacji, które obejrzałem i inne tego typu materiały. Zawsze bardzo dużo i intensywnie się uczyłem, i teraz poniekąd żałuję, że tego wcześniej w żaden sposób nie dokumentowałem, bo &#8211; jak mawia [...]]]></description>
			<content:encoded><![CDATA[<p>No to stało się, założyłem sobie blog.</p>
<p>Od dłuższego czasu brakowało mi miejsca, w którym mógłbym gromadzić swoje notatki, przemyślenia, recenzje książek, odnośniki do prezentacji, które obejrzałem i inne tego typu materiały. Zawsze bardzo dużo i intensywnie się uczyłem, i teraz poniekąd żałuję, że tego wcześniej w żaden sposób nie dokumentowałem, bo &#8211; jak mawia mój młodszy kolega &#8211; po dziewięćdziesiątce pamięć już nie ta i sporo ciekawych rzeczy uleciało. Teraz mam nadzieję, że się to zmieni na lepsze &#8211; ten blog będzie mi służył jako zewnętrzna pamięć oraz świadek moich poszukiwań ciekawych tematów i zagadnień.</p>
<p><em>Czego będą dotyczyły wpisy?</em><br />
Sam jeszcze do końca nie wiem. Zamierzam nadrobić braki w wielu nieznanych mi zupełnie lub znanych bardzo pobieżnie obszarach wiedzy &#8211; głównie z zakresu .NET, ale nie tylko &#8211; chyba już nadszedł czas, aby przyglądnąć się innym technologiom, zwłaszcza webowym. Inwestuję także swój czas w poznawanie języka F# oraz ogólnie języków funkcyjnych. Ostatnio sporo energii poświęcam również zagadnieniom architektonicznym, SOA, DDD, CQRS i innym magicznym skrótom. Odkąd zakupiłem sobie <a href="http://www.amazon.com/gp/product/B002GYWHSQ?ie=UTF8&#038;tag=blackfootpl-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=B002GYWHSQ">grafitowy czytnik Kindle DX 9.7&#8221;</a><img src="http://www.assoc-amazon.com/e/ir?t=blackfootpl-20&#038;l=as2&#038;o=1&#038;a=B002GYWHSQ" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, czytam jak szalony książkę za książką, więc jest szansa na trochę subiektywnych recenzji. Mój zbiór prezentacji z różnorakich konferencji mocno się rozrósł, odsetek tych, które zdołałem już obejrzeć, jest także dosyć wysoki &#8211; postaram się więc zamieścić opisy tych, które najbardziej mi się podobały. Jestem także w trakcie pisania całkiem interesującej aplikacji, w której mam szansę powalczyć z nowymi dla mnie zagadnieniami, więc podejrzewam, że będzie to całkiem ciekawe źródło wpisów. Myślę, że sporo interesujących rzeczy pojawi się również po drodze.</p>
<p>Kategorie oraz tagi wyglądają na razie bardzo ubogo, ale mam nadzieję, że będzie się to zmieniać z tygodnia na tydzień.</p>
<p><strong>No to startujemy&#8230;</strong><br />
<script src="http://www.assoc-amazon.com/s/link-enhancer?tag=blackfootpl-20&amp;o=1" type="text/javascript">
</script><br />
<noscript><br />
<img src="http://www.assoc-amazon.com/s/noscript?tag=blackfootpl-20" alt="" /><br />
</noscript></p>
]]></content:encoded>
			<wfw:commentRss>http://blackfoot.pl/2011/02/przygode-czas-zaczac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

