<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">
<channel>
    <title>.:: strefa ::. - Platforma .NET</title>
    <link>http://strefa.guzowski.info/</link>
    <description>Bazy danych i nie tylko.</description>
    <dc:language>pl</dc:language>
    <generator>Serendipity 1.1.3 - http://www.s9y.org/</generator>
    <pubDate>Fri, 05 Oct 2007 17:31:00 GMT</pubDate>

    <image>
        <url>http://strefa.guzowski.info/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: .:: strefa ::. - Platforma .NET - Bazy danych i nie tylko.</title>
        <link>http://strefa.guzowski.info/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>Źródła niektórych bibliotek .NET Framework będą dostępne</title>
    <link>http://strefa.guzowski.info/archives/81,2007,10,05.html</link>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/81,2007,10,05.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=81</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=81</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Microsoft zdecydował się udostępnić kod źródłowy wraz z komentarzami niektórych bibliotek .NET Framework:&lt;br /&gt;
- .NET Base Class Libraries (System, System.IO, System.Collections, System.Configuration, System.Threading, System.Net, System.Security, System.Runtime, System.Text i pewnie jeszcze kilku innych),&lt;br /&gt;
- ASP.NET (System.Web),&lt;br /&gt;
- Windows Forms (System.Windows.Forms),&lt;br /&gt;
- ADO.NET (System.Data),&lt;br /&gt;
- XML (System.Xml),&lt;br /&gt;
- WPF (System.Windows).&lt;br /&gt;
&lt;br /&gt;
Kod źródłowy zostanie opublikowany na licencji Microsoft Reference License (Ms-RL) wraz z wydaniem .NET Framework 3.5 i Visual Studio 2008. Udostępnienie wyżej wymienionych bibliotek będzie polegać na tym, że w Visual Studio 2008 pobierzemy symbole z jednego z serwerów (pewnie source.msdn.microsoft.com).&lt;br /&gt;
&lt;br /&gt;
Więcej informacji:&lt;br /&gt;
&lt;a href=&quot;http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx&quot;  title=&quot;ScottGu&#039;s Blog: Releasing the Source Code for the .NET Framework Libraries&quot;&gt;ScottGu&#039;s Blog: Releasing the Source Code for the .NET Framework Libraries&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.microsoft.com/resources/sharedsource/licensingbasics/referencelicense.mspx&quot;  title=&quot;Microsoft Reference License (Ms-RL)&quot;&gt;Microsoft Reference License (Ms-RL)&lt;/a&gt; 
    </content:encoded>

    <pubDate>Fri, 05 Oct 2007 19:31:00 +0200</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/81,2007,10,05.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>3 x 2008, czyli premiera Windows Server 2008, SQL Server 2008 i Visual Studio 2008</title>
    <link>http://strefa.guzowski.info/archives/69,2007,07,11.html</link>
            <category>MS SQL Server</category>
            <category>Platforma .NET</category>
            <category>Różne</category>
    
    <comments>http://strefa.guzowski.info/archives/69,2007,07,11.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=69</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=69</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Na międzynarodowej konferencji dla przeszło 10 tysięcy firm partnerskich (Worldwide Partner Conference, WPC) w Denver Microsoft ogłosił, że premiery nowych wersji znanych produktów - systemu operacyjnego Windows Server 2008 (codename &lt;em&gt;Longhorn&lt;/em&gt;), platformy bazodanowej SQL Server 2008 (codename &lt;em&gt;Katmai&lt;/em&gt;) i zintegrowanego środowiska programistycznego Visual Studio 2008 (codename &lt;em&gt;Orcas&lt;/em&gt;) odbędą się 27 lutego 2008 roku w Los Angeles. Wydarzenie to zapoczątkuje serię mniejszych konferencji na poziomie krajowym, na których prezentowane będą nowe produkty.&lt;br /&gt;
&lt;br /&gt;
Więcej informacji:&lt;br /&gt;
&lt;a href=&quot;http://www.microsoft.com/presspass/press/2007/jul07/07-10WPCDay1PartnersPR.mspx&quot;  title=&quot;Microsoft PressPass: Microsoft Executives Outline Next-Generation Business Opportunities for Partners With New Products, Tools and Programs&quot;&gt;Microsoft PressPass: Microsoft Executives Outline Next-Generation Business Opportunities for Partners With New Products, Tools and Programs&lt;/a&gt; 
    </content:encoded>

    <pubDate>Wed, 11 Jul 2007 18:51:00 +0200</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/69,2007,07,11.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Enterprise Library 3.0</title>
    <link>http://strefa.guzowski.info/archives/55,2007,04,13.html</link>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/55,2007,04,13.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=55</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=55</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Na początku kwietnia Microsoft udostępnił trzecią wersję pakietu bibliotek Enterprise Library. EntLib to produkt, który ma ułatwiać developerom implementowanie standardowych funkcjonalności (jak np. cacheowanie) i pomóc w rozwiązywaniu najczęstszych problemów podczas tworzenia dużych aplikacji. Pakiet składa się z 8 bloków podstawowych:&lt;br /&gt;
- Caching Application Block&lt;br /&gt;
- Cryptography Application Block&lt;br /&gt;
- Data Access Application Block&lt;br /&gt;
- Exception Handling Application Block&lt;br /&gt;
- Logging Application Block&lt;br /&gt;
- Policy Injection Application Block&lt;br /&gt;
- Security Application Block&lt;br /&gt;
- Validation Application Block&lt;br /&gt;
&lt;br /&gt;
EntLib wymaga co najmniej .NET Framework 2.0. Do skorzystania z niektórych grup funkcjonalności (Application Block Software Factory, Validation Application Block WCF i Exception Handling Application Block WCF) potrzebny jest .NET Framework w wersji 3.0.&lt;br /&gt;
&lt;br /&gt;
Więcej informacji i pobieranie:&lt;br /&gt;
&lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/aa480453.aspx&quot;  title=&quot;MSDN: Enterprise Library&quot;&gt;MSDN: Enterprise Library&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.microsoft.com/downloads/details.aspx?FamilyID=62EF5F79-DAF2-43AF-9897-D926F03B9E60&amp;amp;displaylang=en&quot;  title=&quot;Download: Enterprise Library 3.0&quot;&gt;Download: Enterprise Library 3.0&lt;/a&gt; 
    </content:encoded>

    <pubDate>Fri, 13 Apr 2007 09:21:00 +0200</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/55,2007,04,13.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Przetwarzanie wyrażeń logicznych</title>
    <link>http://strefa.guzowski.info/archives/42,2007,02,11.html</link>
            <category>Świat Perla</category>
            <category>MS SQL Server</category>
            <category>Platforma .NET</category>
            <category>Różne</category>
    
    <comments>http://strefa.guzowski.info/archives/42,2007,02,11.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=42</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=42</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Ogromna większość technologii programistycznych (języków programowania, języków skryptowych itp.) zakłada specyficzny sposób przetwarzania wyrażeń logicznych zawartych najczęściej w różnego typu instrukcjach warunkowych (IF, WHILE, FOR). Chodzi o to, że zdanie logiczne składające się z kilku wyrażeń, np:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;A OR B OR C&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
jest uwzględniane tylko do momentu, w którym da się określić wartość całego wyrażenia. W powyższym przykładzie moment ten nastąpi już w sytuacji, w której wartość logiczna wyrażenia A będzie prawdziwa (alternatywa jest prawdziwa, gdy prawdziwy jest jeden z jej elementów). Głównym uzasadnieniem takiej obsługi są kwestie wydajnościowe i praktyczne. Opisane podejście do przetwarzania warunków ma jednak szereg konsekwencji, które warto sobie uświadomić. Postaram się zwrócić na nie uwagę bardziej szczegółowo prezentując implementację zasygnalizowanego zagadnienia w kilku środowiskach.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Practical Extraction and Report Language (Perl)&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Spójrzmy na poniższy skrypt:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;#!/usr/bin/perl&lt;br /&gt;
&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my $count = 0;&lt;br /&gt;
my $a = 1;&lt;br /&gt;
&lt;br /&gt;
if ($a != 1 and func() == 2) {&lt;br /&gt;
	 &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
print $count;&lt;br /&gt;
&lt;br /&gt;
sub func&lt;br /&gt;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;$count++;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;return 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Interesuje nas odpowiedź na pytanie, czy funkcja &lt;em&gt;func()&lt;/em&gt; zostanie w ogóle wywołana. Otóż - zgodnie z tym, co napisałem we wstępie - nie zostanie. Nie ma potrzeby sprawdzania wyrażenia z funkcją, gdyż już na podstawie nieprawdziwości wyrażenia &lt;em&gt;$a != 1&lt;/em&gt; (1 != 1) można stwierdzić, że całe zdanie warunku jest fałszywe. Skrypt drukuje więc:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;0&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Trzeba o tym pamiętać umieszczając funkcję w logice instrukcji warunkowych.&lt;br /&gt;
&lt;br /&gt;
W rzeczywistości to właśnie opisana obsługa warunków umożliwia stosowanie konstrukcji typu:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;if (defined $zmienna and $zmienna == 5) { }&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Gdyby za każdym razem przetwarzane było całe wyrażenie, to przy zastosowanym &lt;em&gt;use warnings;&lt;/em&gt; dochodziłoby do monitu:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;Use of uninitialized value in numeric eq (==) at (...)&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
zawsze wtedy, kiedy &lt;em&gt;$zmienna&lt;/em&gt; byłaby undef.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Platforma .NET (C#)&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa jest analogiczna, poniższy program drukuje 0.&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;using System;&lt;br /&gt;
using System.Collections.Generic;&lt;br /&gt;
using System.Text;&lt;br /&gt;
&lt;br /&gt;
namespace ConsoleApplication1&lt;br /&gt;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;class Program&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;public static int count = 0;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;public static int func()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;count++;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;return 2; &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;static void Main(string[] args)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;int a = 1;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;if (a == 1 || func() == 2)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;System.Console.WriteLine(count);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
}&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Podobnie jak w Perlu, w C# (i innych językach .NETowskich) dzięki specyficznej obsłudze wyrażeń logicznych możliwe jest stosowanie konstrukcji:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;if (obj != null &amp;&amp;amp; obj.property == 2) { }&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Różnica między C# i Perlem polega jednak w tym przypadku na tym, że o ile w Perlu użycie niezainicjalizowanej zmiennej skutkuje co najwyżej ostrzeżeniem (warning level), o tyle w .NET użycie nieistniejącego obiektu kończy się rzuceniem wyjątku &lt;em&gt;NullReferenceException()&lt;/em&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;C/C++&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Przykładowy kod w przypadku C:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;#include &lt; stdio.h&gt;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;int count = 0;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;int a = 1;&lt;br /&gt;
		&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;if (a == 1 || func(&amp;count) == 2) { }&lt;br /&gt;
	&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;printf(&quot;%d&quot;, count);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int func(int* pcount) {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;(*pcount)++;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;return 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Jeżeli w powyższym kodzie pierwsze wyrażenie składowe warunku IF zostanie zmienione na &lt;em&gt;1 == 1&lt;/em&gt;, to większość kompilatorów w ogóle nie uwzględni drugiego wyrażenia alternatywy (z funkcją &lt;em&gt;func()&lt;/em&gt;) - skompiluje więc warunek jako zawsze prawdziwy. Można się o tym łatwo przekonać zamieniając dodatkowo nazwę funkcji w warunku na taką, która nie istnieje:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;if (1 == 1 || nie_mam_definicji(&amp;count) == 2) { }&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
W obu przypadkach (zmieniony i niezmieniony kod przykładowy) skompilowany program zwraca 0.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;JavaScript&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Obsługa jest analogiczna:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;&amp;lt;SCRIPT TYPE=&quot;text/javascript&quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
var count = 0;&lt;br /&gt;
var a = 1;&lt;br /&gt;
&lt;br /&gt;
function func() {&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;count++;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;return 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if (a == 1 || func() == 2) { }&lt;br /&gt;
&lt;br /&gt;
alert(count);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/SCRIPT&amp;gt;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Alert prezentuje wartość 0.&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Microsoft SQL Server&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
Jeżeli wywołamy poniższy T-SQL:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;SELECT 0/0&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
SQL Server natychmiast rzuci błędem:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;Msg 8134, Level 16, State 1, Line 1&lt;br /&gt;
Divide by zero error encountered.&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Kiedy jednak dzielenie przez 0 znajdzie się w odpowiednim warunku logicznym:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;IF (1=1 OR 1=0/0)&lt;br /&gt;
PRINT &#039;TRUE&#039;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
błąd nie występuje, gdyż nie dochodzi do wykonania wadliwego kodu. &lt;br /&gt;
&lt;br /&gt;
O ile w przypadku Perla, C czy C# specyficzna ewaluacja warunków logicznych jest czymś pozytywnym, o tyle w świecie baz danych prowadzi do pewnych niekonsekwencji. Trzeba pamiętać, że SQL Server i inne RDBMS implementują logikę trójwartościową (three-valued logic, 3VL). Przestrzeń nie ogranicza się więc do wartości TRUE i FALSE, lecz składa się na nią TRUE, FALSE i UNKNOWN. Może więc dojść do sytuacji, że kiedy - ze względu na operację z NULLem - warunek powinien mieć wartość logiczną UNKNOWN, w praktyce zwraca wartość prawdy. Dokładnie taka sytuacja ma miejsce w poniższym przykładzie:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;DECLARE @a int;&lt;br /&gt;
SET @a = 1;&lt;br /&gt;
&lt;br /&gt;
IF (NOT (@a&lt;&gt;1 AND 1=NULL))&lt;br /&gt;
PRINT &#039;TRUE&#039;;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Warto o tym pamiętać, gdyż NULLe i stany nieokreśloności mogą generować sporą ilość trudno wykrywalnych problemów.&lt;br /&gt;
&lt;br /&gt;
Sposób ewaluacji wyrażeń logicznych jest analogiczny w stosunku do wyżej opisanego w przypadku wszystkich znanych mi technologii (języków). Wiedza o takim sposobie obsługi jest więc całkiem wskazana tym bardziej, że umożliwi ona zapisywanie skomplikowanych warunków logicznych w sposób bardziej wydajny - czyli taki, aby sterując kolejnością wyrażeń składowych jak najwcześniej dało się zaprzeczyć lub uznać za prawdziwy cały warunek. Oczywiście ten swoisty tuning wyrażeń logicznych może mieć miejsce wyłącznie w środowisku, które respektuje kolejność wykonywania wyrażeń składowych zgodnie z ich występowaniem w kodzie (od lewej do prawej). Jest to powszechny standard, ale np. SQL Server się do niego nie stosuje. 
    </content:encoded>

    <pubDate>Sun, 11 Feb 2007 15:02:00 +0100</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/42,2007,02,11.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Garbage collection i słabe referencje (weak references)</title>
    <link>http://strefa.guzowski.info/archives/33,2007,01,06.html</link>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/33,2007,01,06.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=33</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=33</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Różne środowiska uruchomieniowe, w tym także CLR platformy .NET, wykorzystują mechanizm automatycznego zarządzania pamięcią, określany powszechnie jako &quot;odśmiecanie pamięci&quot; (garbage collection). Podstawowym celem zastosowania garbage collection była chęć uwolnienia dewelopera od obowiązku ciągłego myślenia w kategorii skończoności zasobów o przydziale i zwalnianiu dostępnej pamięci. Wpisuje się to oczywiście w ogólną koncepcję tworzenia oprogramowania wg podejścia RAD (Rapid Application Development). Zgodnie z założeniami, w środowisku .NET alokacją i zwalnianiem pamięci zajmuje się specjalny mechanizm - tzw. garbage collector (GC), a programista powinien skupić się na funkcjonalności aplikacji. Nie oznacza to jednak, że możemy zupełnie zapomnieć o kwestiach dotyczących pamięci. GC funkcjonuje w oparciu o zestaw reguł, na podstawie których podejmuje określone działania. Naturalnie reguły te nie są równie efektywne w każdej z możliwych sytuacji, dlatego właśnie świadomy deweloper powinien nauczyć się tak pisać swój kod, żeby w pośredni sposób wpływać na przewidywalne zachowania garbage collectora.&lt;br /&gt;
&lt;br /&gt;
Chciałbym zwrócić uwagę na kilka kwestii związanych z automatycznym zarządzaniem pamięcią na platformie .NET. Tematyka jest bardzo szeroka i wieloaspektowa, dlatego poniższe informacje mogą stanowić jedynie wstęp do bardziej dogłębnej analizy tematu.&lt;br /&gt;
&lt;br /&gt;
Pamięć w sensie funkcjonalnym podzielić możemy na stos (stack) i stertę zarządzaną (managed heap). Typy bezpośrednie (value types, czyli np. zmienne w metodzie) alokowane są na stosie. GC nie ma z nimi za wiele pracy - po opuszczeniu metody pamięć jest w prosty i natychmiastowy sposób zwalniana. Wszystko komplikuje się w przypadku typów referencyjnych, które alokowane są na stercie. Każde utworzenie nowego obiektu powoduje zarezerwowanie określonego obszaru pamięci na stercie (przesuwany jest także wskaźnik alokacji &lt;em&gt;NextObjPtr&lt;/em&gt;, wskazujący następny dostępny adres). O ile moment tworzenia obiektu jest jednoznaczny i trywialny do określenia, o tyle identyfikacja obiektów już niepotrzebnych to działanie o wiele bardziej złożone. Zadanie to GC realizuje poprzez cykliczne sprawdzanie, które obiekty nie są osiągalne z żadnego zasięgu w programie. Odbywa się to na zasadzie wstępnej negacji - początkowo wszystkie obiekty uznawane są za martwe, następnie GC z listy śmierci usuwane te, które w danym momencie mogą być osiągnięte przez kod aplikacji. Pozostałe obiekty przeznaczone są do unicestwienia. Podczas okresowej aktualizacji sterty GC zwalnia bloki pamięci odnoszące się do martwych obiektów. Dodatkowo scala pozostałe bloki tak, by nie pozostawały między nimi żadne wolne przestrzenie. Wiąże się to oczywiście z koniecznością aktualizacji wskaźnika alokacji i koniecznością przeadresowania wszystkich referencji do obiektów, gdyż po migracji bloków zmianie ulegają adresy pamięci. Operacje wykonywane przez GC są dla wnętrzności naszego programu dość rewolucyjne i kosztowne pod względem wydajności. Podczas działania GC może wystąpić chwilowa niepoprawność referencji, pamięć musi więc pozostawać niedostępna dla aplikacji, co jest realizowane przez wstrzymanie wszystkich jej wątków. Ze względu na opisaną charakterystykę pracy i kosztowność operacji, GC uruchamiany jest zasadniczo dopiero w sytuacji braku pamięci na stercie. &lt;br /&gt;
&lt;br /&gt;
Algorytm garbage collection działa w rzeczywistości w nieco bardziej skomplikowany sposób, uwzględniając m.in. tzw. generacje. Możliwe jest także wymuszone uruchomienie GC z kodu aplikacji (&lt;em&gt;System.GC.Collect()&lt;/em&gt;). Wymienione kwestie, jak też inne szczegóły wykraczają jednak poza zakres tego powierzchownego artykułu - zainteresowanych zapraszam do zapoznania się z linkami zebranymi poniżej.&lt;br /&gt;
&lt;br /&gt;
Trzeba pamiętać, że GC zajmuje się &lt;u&gt;zwalnianiem pamięci&lt;/u&gt; zajmowanej przez martwe obiekty, a &lt;u&gt;nie zwalnianiem wszystkich zasobów&lt;/u&gt; przez te obiekty wykorzystywanych. Sami więc musimy zadbać o zwolnienia zasobów niezarządzanych (plikowych, sieciowych, sprzętowych), np. otwartego połączenia do bazy danych. Nie chodzi tutaj wyłącznie o tzw. finalizację (zaimplementowanie finalizatora klasy), która w wielu sytuacjach może okazać się mało efektywna. Lepszym wyjściem będzie oprogramowanie metod Close() i Dispose(), czy stosowanie bloku using.&lt;br /&gt;
&lt;br /&gt;
Ciekawe możliwości oferują tzw. słabe referencje (weak references). Nie jest to pomysł ani nowy, ani specyficzny wyłącznie dla platformy .NET. Słabe referencje spotykamy również w innych technologiach z mechanizmem typu garbage collection (jak Java czy Perl).&lt;br /&gt;
&lt;br /&gt;
Dla jednoznaczności warto uściślić, że silna referencja do obiektu (strong reference) występuje w sytuacji, kiedy obiekt może być osiągnięty z kodu aplikacji. W sytuacji silnej (zwykłej) referencji obiekt jest więc poza zainteresowanie GC. Słaba referencja natomiast to swoisty kompromis - obiekt jest co prawda dostępny dla aplikacji (która może uzyskać do niego silną referencję), ale w każdym momencie GC może go unicestwić. &lt;br /&gt;
&lt;br /&gt;
Pozornie może się wydawać, że nie ma to wielkiego sensu. Są jednak sytuacje, w których opisany kompromis jest całkiem akceptowalny. Słabe referencje świetnie nadają się do obiektów, które zajmują duży obszar pamięci, ale mogą być łatwo odtworzone. Wprowadza to swoistą elastyczność obsługi do naszej aplikacji. Kiedy zabraknie pamięci, obiekt ze słabą referencją zostanie unicestwiony przez GC i na stercie przybędzie potrzebnej w danym momencie wolnej przestrzeni. Jeżeli obiekt będzie potrzebny ponownie, zostanie w prosty sposób zrekonstruowany. W sytuacji dostatecznej ilości wolnej przestrzeni na stercie, obiekt nie zostanie zniszczony, aplikacja będzie więc go mogła użyć natychmiast po wykorzystaniu słabej referencji.&lt;br /&gt;
&lt;br /&gt;
Słabych referencji nie należy stosować przy małych obiektach jak też nie są one remedium na wszystkie problemy wydajnościowe aplikacji - w każdym razie na pewno nie zastąpią rozsądnego i przemyślanego cacheowania.&lt;br /&gt;
&lt;br /&gt;
Więcej informacji:&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx&quot;  title=&quot;MSDN: Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework&quot;&gt;MSDN: Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/&quot;  title=&quot;MSDN: Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework&quot;&gt;MSDN: Garbage Collection—Part 2: Automatic Memory Management in the Microsoft .NET Framework&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/ms404247.aspx&quot;  title=&quot;MSDN: Using Weak References &quot;&gt;MSDN: Using Weak References &lt;/a&gt; 
    </content:encoded>

    <pubDate>Sat, 06 Jan 2007 18:08:00 +0100</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/33,2007,01,06.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Deduplikacja danych: .NET vs Perl</title>
    <link>http://strefa.guzowski.info/archives/27,2006,11,16.html</link>
            <category>Świat Perla</category>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/27,2006,11,16.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=27</wfw:comment>

    <slash:comments>2</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=27</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Systemy informatyczne przetwarzają coraz większe ilości danych, w naturalny sposób pojawia się więc coraz większa potrzeba ich automatycznej analizy i obróbki. Deweloperzy związani z bazami danych muszą tworzyć specyficzne, dedykowane rozwiązania, a wybór odpowiedniej technologii to praktycznie klucz do sukcesu. Chciałbym porównać dwie wybrane platformy - .NET i Perl - w hipotetycznym scenariuszu automatycznego przetwarzania danych.&lt;br /&gt;
&lt;br /&gt;
Wspomniany scenariusz zakłada potrzebę wyznaczenia rekordów podobnych w bazie klientów, a dokładniej - w tabeli, która zawiera 10000 wierszy z danymi teleadresowymi (przykładowe kolumny: nazwa, miejscowość, adres, kod, nip). Dane w bazie są zwielokrotnione, tzn. kilka rekordów w rzeczywistości opisuje jednego i tego samego klienta (zapisanego oczywiście w różny sposób, np. &quot;FIRMA HERKULES&quot;, &quot;HERKULES S.C.&quot;, &quot;HERKULES - SKLEP&quot;; analogicznie z danymi adresowymi: &quot;WIEJSKA 15&quot;, &quot;ULICA WIEJSKA&quot; itd.). Aby zrealizować cel, do tabeli zostanie dodana kolumna unikalnego identyfikatora, a algorytm zapełni ją odpowiednimi wartościami, przydzielając rekordom dostatecznie podobnym taki sam identyfikator. Zakładamy ponadto warunek brzegowy (minimalizacja ryzyka błędu): rekordy oznaczone jako podobne muszą posiadać identyczny NIP.&lt;br /&gt;
&lt;br /&gt;
Zadanie opisane wyżej to klasyczna deduplikacja danych. Od prawie 2 lat zajmuję się m.in. procesami inteligentnej analizy, przetwarzania danych i obserwuję w ostatnim czasie znaczący, dynamiczny wzrost popularności tej tematyki. Złoty wiek różnorodnych automatów właśnie się rozpoczął.&lt;br /&gt;
&lt;br /&gt;
Wracając do naszego scenariusza, można sobie wyobrazić co najmniej kilka koncepcji algorytmu deduplikacji, oczywiście każdy z nich ma swoje mocne i słabe strony. Skupiamy się na technologii, a nie na funkcjonalnościach - więc dodam tylko, że do oceny zgodności poszczególnych pól użyłem metody Levenshtein-Distance (google zaprasza zainteresowanych).&lt;br /&gt;
&lt;br /&gt;
Środowisko testowe wyglądało następująco: serwer Windows Server 2003 SE 32bit, baza danych SQL Server 2005 SP1, wszystko postawione na jednej maszynie (na której uruchamiane były również testowe implementacje). Jak widać środowisko zostało dobrane tak, żeby lekko faworyzować platformę .NET. Implementacja algorytmu w CLR (język C#) to klasyczna aplikacja obiektowa z providerem OLE DB (natywne rozwiązanie względem SQL Servera).&lt;br /&gt;
&lt;br /&gt;
Algorytm został również zaimplementowany w Perlu (wersja 5.8.8), dostępem do danych zajmował się moduł DBI działający na providerze ODBC. &lt;br /&gt;
&lt;br /&gt;
Mamy więc pojedynek technologii, za którą stoją miliardy dolarów w jej naturalnym środowisku - i - technologii open source, która dzięki wieloletniej pracy rzeszy ludzi została wysoce zoptymalizowana do przetwarzania danych, a wyrażenia regularne traktuje tak samo natywnie jak choćby instrukcję warunkową IF. Poniżej przedstawiam wyniki:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;(średni czas dla 3 prób)&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;PERL:&lt;br /&gt;
81 s&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
.NET:&lt;br /&gt;
127 s&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Wyraźnie zwyciężył więc Perl, który zadanie wykonał o 55% szybciej niż konkurent (jakość była jednakowa w obydwu przypadkach, zgodnie z założeniem). Nie pierwszy raz przekonałem się, że Practical Extraction and Report Language nie ma sobie równych wśród technologii do przetwarzania danych. Warto też dodać, że obydwie implementacje powstały w tak samo krótkim czasie, mimo że do stworzenia kodu w Perlu wykorzystałem zwykły edytor tekstowy, a do .NET - potężne Visual Studio 2005 z pełnym intellisense i innymi programistycznymi udogodnieniami. 
    </content:encoded>

    <pubDate>Thu, 16 Nov 2006 22:39:00 +0100</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/27,2006,11,16.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Bezpieczeństwo kodu źródłowego</title>
    <link>http://strefa.guzowski.info/archives/26,2006,11,11.html</link>
            <category>Bezpieczeństwo</category>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/26,2006,11,11.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=26</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=26</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Platforma .NET dostarcza deweloperom wielu nowych możliwości, ułatwień i ulepszeń, także w aspekcie bezpieczeństwa - zwiększając tym samym ochronę szeroko pojętych dóbr intelektualnych. Współczesne organizacje poświęcają wiele energii dbając o to, by określona informacja nie dotarła do osób niepowołanych. Stosowane są zaawansowane metodyki bezpieczeństwa, szyfrowanie, ścisła identyfikacja zasobów, firewalle itd. Tymczasem dając użytkownikowi do ręki skompilowaną do kilku plików DDL i pliku EXE aplikację .NET - dajemy mu jednocześnie na talerzu co najmniej jej algorytmiczne tajemnice, a często także szereg innych cennych informacji.&lt;br /&gt;
&lt;br /&gt;
Wszystkie .NETowskie asemblacje objęte są tzw. mechanizmem reflection, który jest interfejsem do pozyskania szczegółowych metainformacji dotyczących wszystkich klas w danej assembly. To cena, jaką płacimy m.in. za intellisense w Visual Studio.&lt;br /&gt;
&lt;br /&gt;
Wprawdzie self-desribing assemblies nie ujawniają własnego kodu MSIL (Microsoft Intermediate Language), jednak droga do jego pozyskania dla amatorów cudzego kodu źródłowego jest banalnie prosta. Jeszcze łatwiej natomiast zamienić instrukcje języka pośredniego na kod języka wyższego poziomu - C#, VB.NET czy managed C++. Razem z .NET Framework dostarczany jest IL Assembler - to oczywiste. Być może mniej oczywisty jest fakt, że wraz z .NET Framework SDK (dołączonym m.in. do Visual Studio), dostarczany jest także IL Disassembler. Wystarczy więc uruchomić plik &lt;em&gt;lidasm.exe&lt;/em&gt; i już mamy okienkowy interfejs prowadzący wprost do kodu pośredniego dowolnej aplikacji .NET, nie robiąc przy tym kompletnie nic nielegalnego. IL Disassembler jest jednak troszkę toporny, w końcu dlaczego nie mielibyśmy od razu otrzymać kodu w dowolnym języku wyższego poziomu (do wyboru), wraz z całą hierarchią obiektów, typami, metodami w przyjaznym dla oka GUI? Nic bardziej prostszego, programów tego typu jest całkiem sporo. Wystarczy polecić Lutz Roeder&#039;s .NET Reflector (&lt;a href=&quot;http://www.aisto.com/roeder/dotnet/&quot;  title=&quot;Lutz Roeder&#039;s .NET Reflector homepage&quot;&gt;strona domowa&lt;/a&gt;). Na życzenie program ten wygeneruje nam w pełni funkcjonalny projekt, który natychmiast możemy otworzyć w Visual Studio.&lt;br /&gt;
&lt;br /&gt;
Okrutna prawda jest taka, że każdy program można poddać mniej lub bardziej skutecznej disasemblacji, przy czym jest to o wiele trudniejsze w przypadku binarki Win32, a o wiele łatwiejsze w przypadku aplikacji .NET (analogicznie: Javy czy Perla). Potwierdza to starą zasadę, że nie ma zabezpieczenia, którego nie dałoby się złamać. Jedyne co można zrobić, to maksymalnie utrudnić reverse engineering, mając nadzieję, że skutecznie zniechęci to ewentualnych zainteresowanych. Jeżeli już musimy udostępnić komuś bezpośrednio skompilowany program, to zadbajmy chociaż o maksymalne &quot;zaciemnienie&quot; jego kodu źródłowego. Można użyć do tego celu jednego z powszechnie dostępnych obfuscatorów, np. programu Dotfuscator (&lt;a href=&quot;http://www.preemptive.com/products/dotfuscator/&quot; title=&quot;Dotfuscator homepage&quot;&gt;strona domowa&lt;/a&gt;, polecany przez Microsoft). Kod źródłowy zostanie wtedy odpowiednio zmodyfikowany: obfuscator zamieni nazwy zmiennych, obiektów, metod na niezrozumiałe dla człowieka sekwencje znaków, zaszyfruje wartości stringów, zastosuje instrukcje goto utrudniające zrozumienie kolejności instrukcji itp. Oczywiście wszystkie wymienione czynności nie będą wpływały na efekt działania skompilowanej aplikacji, chodzi tylko o jak największe skomplikowanie analizy kodu pozyskanego przez disasemblację. Trzeba jednak od razu zaznaczyć, że istnieje co najmniej kilka deobfuscatorów, które potrafią przywrócić kod do całkiem czytelnej formy...&lt;br /&gt;
&lt;br /&gt;
Szczerze mówiąc, nie ma dobrej metody na ochronę kodu aplikacji .NET, jeżeli fizycznie przekazujemy skompilowany program osobie trzeciej. Trzeba mieć to na uwadze projektując rozwiązania z zastosowaniem tej technologii. Nie zawsze jednak sytuacja wymaga takiego kroku - wtedy otwiera się obszar dla zastosowania technologii webowej lub usług terminalowych. Może i są to rozwiązania mniej wygodne dla użytkownika, ale nie ma przecież nic za darmo. 
    </content:encoded>

    <pubDate>Sat, 11 Nov 2006 14:36:00 +0100</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/26,2006,11,11.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>Czas wykonania bloku kodu</title>
    <link>http://strefa.guzowski.info/archives/18,2006,10,12.html</link>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/18,2006,10,12.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=18</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=18</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Zadanie: określić jak długo wykonywał się dowolny fragment kodu. Interesuje nas czas w sekundach, który można od razu wyświetlić w dowolnej kontrolce (rzutowanie na string). Poniżej kod w C#:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;long Ticks = System.DateTime.Now.Ticks;&lt;br /&gt;
// początek kodu objętego pomiarem&lt;br /&gt;
for (int i=0;i&lt;1000000;i++)&lt;br /&gt;
{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;i = i+1;&lt;br /&gt;
}&lt;br /&gt;
// koniec kodu objętego pomiarem&lt;br /&gt;
Ticks = System.DateTime.Now.Ticks - Ticks;&lt;br /&gt;
string strSeconds = new System.TimeSpan(Ticks).TotalSeconds.ToString(); &lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Struktura TimeSpan przechowuje czas w postaci określonej liczby tzw. ticków (1 tick = 100 nanosekund), które w powyższym przykładzie przekazywane są do konstruktora za pomocą zmiennej &lt;em&gt;Ticks&lt;/em&gt; (typ long integer). TimeSpan udostępnia czas w bardziej dla człowieka zrozumiałej formie przy pomocy kilku property methods:&lt;br /&gt;
- TotalMilliseconds&lt;br /&gt;
- TotalSeconds&lt;br /&gt;
- TotalMinutes&lt;br /&gt;
- TotalHours&lt;br /&gt;
- TotalDays 
    </content:encoded>

    <pubDate>Thu, 12 Oct 2006 20:01:00 +0200</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/18,2006,10,12.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>
<item>
    <title>ASP.NET - DataGrid i własne nagłówki</title>
    <link>http://strefa.guzowski.info/archives/11,2006,10,01.html</link>
            <category>Platforma .NET</category>
    
    <comments>http://strefa.guzowski.info/archives/11,2006,10,01.html#comments</comments>
    <wfw:comment>http://strefa.guzowski.info/wfwcomment.php?cid=11</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://strefa.guzowski.info/rss.php?version=2.0&amp;type=comments&amp;cid=11</wfw:commentRss>
    

    <author>nospam@example.com (Marcin Guzowski)</author>
    <content:encoded>
    Załóżmy następujący, całkiem popularny scenariusz: ASP.NET 1.1/2.0, kontrolka DataGrid i bindowany do niej DataSet lub inny obiekt z danymi pobranymi z BD (DataTable, DataView). Interesuje nas sposób wpływania na nagłówki grida tak, aby możliwe było przykładowo wprowadzenie dwuwierszowych komórek w nagłówkach i/lub łączenie odpowiednich komórek, tj.:&lt;br /&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://strefa.guzowski.info/img/custom_headers.gif&quot; vspace=&quot;15&quot; alt=&quot;&quot; border=&quot;0&quot;  /&gt;&lt;/p&gt;Domyślnie DataGrid tworzy nagłówki kolumn w jednym wierszu na podstawie kolekcji kolumn ze źródła danych (czyli np. &lt;em&gt;DataView.Table.Columns&lt;/em&gt;). Aby to naturalne zachowanie zostało zmienione, należy przejąć kontrolę nad renderowaniem grida. Wykorzystamy do tego celu metodę &lt;em&gt;SetRenderMethodDelegate&lt;/em&gt;, która oddeleguje obsługę renderowania grida &lt;em&gt;dgGrid&lt;/em&gt; na naszą metodę &lt;em&gt;GridRendering&lt;/em&gt;:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;// najbezpieczniej umieścić po wywołaniu DataBind()&lt;br /&gt;
dgGrid.&lt;strong&gt;SetRenderMethodDelegate&lt;/strong&gt;(new System.Web.UI.RenderMethod (GridRendering));&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Teraz pozostaje tylko przygotować metodę &lt;em&gt;GridRendering&lt;/em&gt;, która będzie odpowiadała za zbudowanie grida. Tym samym schodzimy na niższy poziom procesu powstawania strony aspx, gdzie grid jest po prostu zbiorem odpowiednich dyrektyw języka HTML. Dzięki temu zyskujemy dostęp do wszystkich możliwości wpływania na layout, jakie daje nam HTML, CSS czy JavaScript. Przykładowy kod metody może wyglądać tak:&lt;br /&gt;
&lt;p class=&quot;code&quot;&gt;// using System.Web.UI;&lt;br /&gt;
// using System.Web.UI.WebControls;&lt;br /&gt;
private void GridRendering (HtmlTextWriter writer, Control ctrl)&lt;br /&gt;
{	&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;// nagłówki&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;string header = @&quot;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td colspan=&quot;&quot;2&quot;&quot;&amp;gt;A&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td colspan=&quot;&quot;2&quot;&quot;&amp;gt;B&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;lt;tr&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td&amp;gt;C&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td&amp;gt;D&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td&amp;gt;E&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;lt;td&amp;gt;F&amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;lt;/tr&amp;gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;writer.Write(@&quot;&amp;lt;table border=&quot;&quot;1&quot;&quot;&amp;gt;&quot;);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;writer.Write(header);&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;// pozostałe komórki&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;Control GridControl = ctrl.Controls[0];&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;foreach (Control ctl in GridControl.Controls)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;// rzutowanie&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;DataGridItem item = (DataGridItem)ctl;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;// sprawdzenie typu komórki - aby pominąć nagłówki&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;if (item.ItemType != ListItemType.Header) &lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;{&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;// ustawienie stylu CSS dla komórki i rendering&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;item.Attributes.Add(&quot;class&quot;,&quot;nazwa_CSS&quot;);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;item.RenderControl(writer);&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;}&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;writer.Write(&quot;&amp;lt;/table&amp;gt;&quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
Metoda &lt;em&gt;GridRendering&lt;/em&gt; najpierw drukuje zdefiniowane przez nas nagłówki kolumn - ich struktura/liczba musi być dostosowana do ilości kolumn w źródle danych, następnie wykonana zostaje pętla po pozostałych komórkach. Nie musimy dla nich za każdym razem drukować tagów HTML (budować elementów html-owej tabeli), wystarczy wywołanie metody &lt;em&gt;RenderControl(writer)&lt;/em&gt;. Dodatkowo, aby ułatwić zarządzanie layoutem z poziomu CSS, do każdej komórki dodawany jest odpowiedni atrybut &lt;em&gt;class&lt;/em&gt;. Oczywiście atrybut ten może być również dodany do kodu HTML samego nagłówka (zmienna &lt;em&gt;header&lt;/em&gt;).&lt;br /&gt;
&lt;br /&gt;
Możliwości samego rozwiązania są bardzo duże, można np. dynamicznie tworzyć złożone nagłówki, a od tego już tylko krok do tabeli przestawnej. Można również dowolnie kreować całego grida i tworzyć na jego bazie własne atrakcyjne i dostosowane do specyficznych potrzeb kontrolki. 
    </content:encoded>

    <pubDate>Sun, 01 Oct 2006 21:20:00 +0200</pubDate>
    <guid isPermaLink="false">http://strefa.guzowski.info/archives/11,2006,10,01.html</guid>
    <creativeCommons:license>http://creativecommons.org/licenses/by/1.0/</creativeCommons:license>
</item>

</channel>
</rss>