<?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>kodehoved</title>
	<atom:link href="http://kodehoved.dk/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://kodehoved.dk</link>
	<description>kode og meninger, meninger om kode</description>
	<lastBuildDate>Thu, 19 Aug 2010 13:27:07 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Nyheder i C# 4 &#8211; syvende del: Varians</title>
		<link>http://kodehoved.dk/?p=581</link>
		<comments>http://kodehoved.dk/?p=581#comments</comments>
		<pubDate>Thu, 19 Aug 2010 13:27:07 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[.NET 4.0]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=581</guid>
		<description><![CDATA[Det er blevet tid til sidste indlæg i min serie om nyheder i C# 4. Denne gang skal det handle om varians eller mere specifikt ko- og kontravarians.
Inden C# 4 kom på gaden var dette noget, der blev omtalt en hel del, men i realiteten er de introducerede forbedringer af den type, hvor vi egentlig [...]]]></description>
			<content:encoded><![CDATA[<p>Det er blevet tid til sidste indlæg i min serie om nyheder i C# 4. Denne gang skal det handle om varians eller mere specifikt ko- og kontravarians.</p>
<p>Inden C# 4 kom på gaden var dette noget, der blev omtalt en hel del, men i realiteten er de introducerede forbedringer af den type, hvor vi egentlig ikke behøver at kende detaljerne. Vi kan blot glæde os over, at tidligere problemfyldte konstruktioner nu fungerer som forventet. </p>
<p>Lad os først få de relevante definitioner på plads for varians:</p>
<p><strong>Kovarians</strong> vil sige, at vi kan konvertere en ”mindre” type til en ”større” type. Eksempelvis kan vi konvertere fra <code>Int32</code> til <code>Int64</code>.</p>
<p><strong>Kontravarians</strong> vil sige, at vi kan konvertere fra en ”større” type til en ”mindre” type. C# kræver eksplicit konvertering i dette tilfælde, da vi risikerer at miste data. Konverterer vi således fra <code>Int64</code> til <code>Int32</code>, kræver C# at vi laver et cast af værdien til <code>Int32</code>. </p>
<p>Ideen bag de introducerede features er at tillade disse konverteringer på en sikker måde.</p>
<h3>Array er kovariant</h3>
<p>C# har understøttet kovarians for arrays siden version 1 men desværre ikke uden problemer. </p>
<p>Betragt nedenstående klassehierarki.</p>
<pre class="syntax-highlight:c#">
public class Creature {
}

public class Monster : Creature {
   public override string ToString() { return &quot;Argh!!&quot;; }
}

public class Vampire : Monster {
   public override string ToString() { return &quot;I Vant Yor Blod&quot;; }
}

public class Zombie : Monster {
   public override string ToString() { return &quot;Braaaaiins!&quot;; }
}
</pre>
<p><code>Monster</code> er en specialisering af <code>Creature</code>, og <code>Zombie</code> og <code>Vampire</code> er yderligere specialiseringer af <code>Monster</code>. Som følge af konventionerne for arv, er enhver <code>Zombie</code> således et <code>Monster</code> og et <code>Creature</code>. Ligeledes er enhver <code>Vampire</code> et <code>Monster</code> og et <code>Creature</code>.  Har vi en instans af <code>Zombie</code>, kan vi således tillade os at betragte den som enten <code>Zombie</code>, <code>Monster</code> eller <code>Creature</code>. </p>
<p>Opretter vi et array af <code>Vampire</code>, burde det således være i orden at betragte det som et array af <code>Monster</code>, eftersom <code>Vampire</code> er en specialisering af <code>Monster</code>. Nedenstående kode er derfor tilladt.</p>
<pre class="syntax-highlight:c#">
Vampire[] vampires = new Vampire[1];
Monster[] monsters = vampires;
</pre>
<p>Så langt, så godt. Men <code>Zombie</code> er jo også et <code>Monster</code>, så hvad sker der, hvis vi smider en <code>Zombie</code> i vores array?</p>
<pre class="syntax-highlight:c#">
monsters[0] = new Zombie();
</pre>
<p>Compileren tillader dette, da <code>Zombie</code> jo er en specialisering af <code>Monster</code>. Afviklingsmiljøet opdager dog, at vi nu har en <code>Zombie</code> i vores <code>Vampire[]</code> og smider en <code>ArrayTypeMismatchException</code>. Ups!</p>
<h3>Problemet og løsningen</h3>
<p>Hvorfor er ovenstående et problem? Når vi kan indsætte en instans af <code>Zombie</code> i et array af <code>Vampire</code>, kan vi komme til at referere denne via en <code>Vampire</code>-reference, og det er som bekendt ikke tilladt i C# og derfor smider afviklingsmiljøet en exception. Heldigvis er denne form for varians kun understøttet for array. Forsøger vi således ovenstående med <code>List<T></code>, kommer vi ikke langt. </p>
<pre class="syntax-highlight:c#">
List&lt;Vampire&gt; vampires = new List&lt;Vampire&gt;();
List&lt;Monster&gt; monsters = vampires; // compilefejl
</pre>
<p>Ovenstående oversætter således ikke. Men hvorfor egentlig ikke? Hvorfor kan vi ikke anskue en samling af <code>Vampire</code> som en samling af <code>Monster</code>, når vi kan betragte en enkelt instans af <code>Vampire</code> som en instans af <code>Monster</code>?</p>
<p>Problemet er at array tillader, at vi ændrer indholdet, så hvis vi ønsker at betragte en samling af <code>Vampire</code> som en samling af <code>Monster</code>, er vi nødt til at gøre det på en måde, så vi ikke kan ændre elementerne som ovenfor.</p>
<p><code>IEnumerable&lt;T&gt;</code> tillader os at gennemløbe en samling af objekter, uden at vi kan ændre denne. Så hvis vi ændrede eksemplet fra at bruge array til at bruge <code>IEnumerable&lt;T&gt;</code>, kunne det således ud:</p>
<pre class="syntax-highlight:c#">
List&lt;Vampire&gt; vampires = new List&lt;Vampire&gt;();
IEnumerable&lt;Monster&gt; monsters = vampires;
</pre>
<p>Desværre virker ovenstående ikke i tidligere version af C#, for skønt vi ved, at vi ikke kan ændre indholdet via en <code>IEnumerable&lt;T&gt;</code>-reference, er compileren desværre uvidende på dette punkt. Vi mangler altså en måde at synliggøre dette over for compileren.</p>
<p>I .NET 4 er <code>IEnumerable&lt;T&gt;</code> og flere andre typer således blevet opdateret med denne information via en ny syntaks til understøttelse af ko- og kontravarians. Den opdaterede definition af <code>IEnumerable&lt;T&gt;</code> er som følger:</p>
<pre class="syntax-highlight:c#">
IEnumerable&lt;out T&gt;
</pre>
<p><code>out</code> indikerer, at vores instans af <code>T</code> kun bliver brugt som output. Vi kan altså få lov at løbe en samling af T igennem og betragte hvert element som instanser af <code>T</code>s baseklasse, fordi elementerne kun optræder som output. </p>
<p>På samme vis er f.eks. <code>Action&lt;T&gt;</code> blevet opdateret som følger:</p>
<pre class="syntax-highlight:c#">
Action&lt;in T&gt;
</pre>
<p>Her angiver <code>in</code>, at instanser af <code>T</code> kun bliver brugt som input til metoden, og dermed kan vi tillade følgende:</p>
<pre class="syntax-highlight:c#">
Action&lt;Monster&gt; write_monster = m =&gt; { Console.WriteLine(m); };
Action&lt;Vampire&gt; write_vampire = write_monster;
</pre>
<p>Eftersom <code>Vampire</code> er en specialisering af <code>Monster</code>, kan vi betragte en metode, der tager en instans af <code>Vampire</code> som input, som en gyldig variant af en metode, der tager en instans af <code>Monster</code> som input, eftersom alle instanser af <code>Vampire</code> også er en instans af <code>Monster</code>, og dermed har vi fået en kontravariant version af <code>Action&lt;T&gt;</code>. </p>
<h3>Afrundning og næste punkt på programmet</h3>
<p>Ko- og kontravarians er kun understøttet for interfaces og delegate-typer, og der skal naturligvis findes en gyldig referencekonvertering mellem de involverede typer, for at det kan lade sig gøre. Ydermere er ko- og kontravarians ikke understøttet for <code>ref</code> og <code>out</code>. </p>
<p>Der er flere detaljer omkring varians, men jeg runder min gennemgang af her. Det er ikke nødvendigt, at forstå samtlige finurligheder for at glæde sig over, at visse oplagte konstruktioner nu er understøttet. </p>
<p>Dermed er vi nået til enden af min gennemgang af nyheder i C# 4. </p>
<p>Jeg er ved at forberede en <a href="https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032456025&#038;culture=da-dk">TechTalk om PFX</a> (tag jer ikke af overskriften, der er et eller andet galt med Microsofts event-system), så de næste mange indlæg kommer til at omhandle parallel programmering og de nye muligheder i .NET 4 og VS2010. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=581</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resultatet af kodegolfkonkurrencen</title>
		<link>http://kodehoved.dk/?p=572</link>
		<comments>http://kodehoved.dk/?p=572#comments</comments>
		<pubDate>Fri, 30 Jul 2010 18:32:15 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[For sjov]]></category>
		<category><![CDATA[kodehoved.dk]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=572</guid>
		<description><![CDATA[Konkurrence er slut, og vinderen er fundet, men inden vi kommer så langt, skal jeg først og fremmest sige tak til alle jer, der har indsendt bidrag. Sommervarme og ferie til trods har jeg modtaget ikke mindre end 30 løsninger på udfordringen denne gang og flere af dem har tilmed været igennem adskillige revisioner. Jeg [...]]]></description>
			<content:encoded><![CDATA[<p>Konkurrence er slut, og vinderen er fundet, men inden vi kommer så langt, skal jeg først og fremmest sige tak til alle jer, der har indsendt bidrag. Sommervarme og ferie til trods har jeg modtaget ikke mindre end 30 løsninger på udfordringen denne gang og flere af dem har tilmed været igennem adskillige revisioner. Jeg er imponeret! Tusind tak fordi I ville være med. </p>
<p>Gennemsnittet for løsningerne ligger på 185 anslag, og der er ikke mindre end syv løsninger på under 140 anslag! 29 ud af 30 løsninger klarer alle mine test cases, så vinderen er altså fundet blandt de 29.</p>
<p>Der er rigtig mange gode og kreative ideer. Flere har været forbi den nye <code>Zip</code>-metode, og LINQ er i det hele taget pænt repræsenteret i løsningerne. Der er brugt mange forskellige datastrukturer så som arrays, <code>List</code>, <code>Stack</code> og sågar <code>string</code>. Vinderen benytter LINQ og <code>string</code>.</p>
<p>Nok snak, lad os se vinderen. Med blot <strong>132 anslag</strong>:</p>
<pre class="syntax-highlight:c#">
public static int[] MadsOgPeterSandbergBrun_Add(int[] a,int[] b){
   var c=&quot;&quot;;
   for(int o=a.Length,p=b.Length,s=0;-o-p&lt;(s=s/10+(0&lt;o?a[--o]:0)+(0&lt;p?b[--p]:0));)
      c=s%10+c;
   return c.Select(i=&gt;i-48).ToArray();
}
</pre>
<p><strong>Tillykke til Mads og Peter Sandberg Brun</strong>! Der er et stk. Visual Studio 2010 Ultimate + MSDN på vej til jer. </p>
<p>Resten af feltet ser ud som følger:</p>
<pre>
<strong>Mads og Peter Sandberg Brun            132</strong>
Jacob Korsgaard                        135
Jørgen Ulrik B. Krag (Jubk)            135
Asger Hallas  og Lars Udengaard        135
Fredrik Olsson                         138
Mogens Heller Grabe (Mookid8000)       138
Ole Tolshave                           139
Jan Jensen (JanJ)                      141
Niels Rasmussen (NTR)                  151
Steffen Holmslykke (SNH)               153
Asger Hallas                           157
Mads Mau Pedersen (MMP)                158
Jesper Harder (JHD)                    158
Daniel Brixen                          169
Anders Uhl Pedersen (Aup)              170
Jonathan Jørgensen (Jonathan)          170
Jesper Alf Dam (Jalf)                  176
Christian Rysgaard (CER)               183
Morten Gejl (MGE)                      193
Mads Hedegaard                         195
Carsten Hess                           196
Brian Vestergaard Andersen             208
Anders Reimer                          218
Dennis Riis                            226
Martin Faartoft                        227
Allan Tech                             248
Martin Larsen                          287
Simon Kristensen (Imonsei)             289
Claus Jensen                           296
Daniel Mellgaard Frost (Danielovich)   229 (fejler)
</pre>
<p>Jeg har lavet <a href="/download/codegolf2010-all.txt">en fil med alle bidragene</a>, så I kan få ideer til fremtidige kodegolfturneringer.  </p>
<p>Endnu en gang tak til jer alle!</p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=572</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>En overraskelse og 1000+ doubles</title>
		<link>http://kodehoved.dk/?p=562</link>
		<comments>http://kodehoved.dk/?p=562#comments</comments>
		<pubDate>Fri, 23 Jul 2010 20:53:25 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Array]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Tip]]></category>
		<category><![CDATA[WTF?!]]></category>
		<category><![CDATA[WinDbg]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=562</guid>
		<description><![CDATA[Dette indlæg rummer egentlig ingen ny viden, men på trods af at jeg efterhånden har brugt lang tid på finurlige detaljer omkring .NETs afviklingsmiljø, er jeg først nu stødt på denne detalje, så set i det lys vil jeg tillade mig at betegne emnet for dette indlæg som esoterisk og gentage noget, der muligvis ikke [...]]]></description>
			<content:encoded><![CDATA[<p>Dette indlæg rummer egentlig ingen ny viden, men på trods af at jeg efterhånden har brugt lang tid på finurlige detaljer omkring .NETs afviklingsmiljø, er jeg først nu stødt på denne detalje, så set i det lys vil jeg tillade mig at betegne emnet for dette indlæg som esoterisk og gentage noget, der muligvis ikke er nyt for alle. </p>
<p>Som det forhåbentlig er kendt for læserne af denne blog, foregår dynamisk allokering af hukommelse i .NET enten i generation 0 af heapen eller på Large Object Heap (LOH) i fald den allokerede instans er på 85.000 bytes eller mere.</p>
<p>Derfor vil <code>small</code> pege på et array allokeret i generation 0 og <code>large</code> pege på et array allokeret på LOH i nedenstående eksempel.</p>
<pre class="syntax-highlight:c#">
var small = new byte[1000];
var large = new byte[85000];
</pre>
<p>Det kan vi verificere via WinDbg eller ved at kalde <code>GC.GetGeneration()</code>, der som forventet returnerer henholdsvis 0 og 2 for de to referencer (bemærk, at metoden ikke skelner mellem generation 2 og LOH, da de i forhold til garbage collection behandles i samme ombæring). Bruger vi debuggeren, får vi lidt mere nøjagtig information, og her kan vi se, at <code>large</code> faktisk peger på en instans på LOH.</p>
<p>Gentager vi øvelsen for <code>double[]</code>, burde vi igen kunne forudsige placeringen af de enkelte instanser. En <code>double</code> fylder 8 bytes, så for at komme over den magiske grænse, skal vi have et array med lidt over 10.000 elementer, lad os bare sige 11.000. Med det in mente burde vi altså kunne konkludere at <code>small</code> og <code>large</code> endnu en gang peger på instanser i henholdsvis generation 0 og på LOH.</p>
<pre class="syntax-highlight:c#">
var small = new double[1000];
var large = new double[11000];
</pre>
<p>Det er bare ikke sådan det forholder sig. <em>Begge arrays bliver allokeret på LOH!</em> </p>
<p>CLRen benytter nemlig en forholdsvis esoterisk optimering i dette tilfælde. Arrays af <code>double</code> med 1000 eller flere elementer bliver mod forventning altid allokeret på LOH. Det er nyt for mig, men hvis man nærlæser kommentarerne til <a href="http://blogs.msdn.com/b/maoni/archive/2006/04/18/large-object-heap.aspx">dette gamle blogindlæg</a>, kan man se, at det er ”by design”. Det er altså ikke en fejl, det er en feature. </p>
<p>Argumentationen er, at objekter på LOH altid ligger på 8 bytes skel, og derfor giver bedre performance ved opslag af elementerne. Jeg har ikke kunne finde nogen forklaring på, hvorfor grænsen på 1000 elementer er valgt, men sådan forholder det sig nu engang.</p>
<p>Det er fristende at prøve, om vi kan eftervise effekten af denne optimering, men det er ikke let i praksis, da vi har meget begrænset kontrol over og indsigt i allokering og adresselæsninger i managed code, så derfor må vi tage Microsofts ord for pålydende her. </p>
<p>Konsekvenserne af denne optimering kan være mange og ikke alle nødvendigvis til vores fordel. Hvis vi antager, at optimeringen har sin berettigelse, så må vi gå ud fra, at læsning af elementerne i et <code>double[]</code>, nyder gavn af den gunstige placering i hukommelsen. </p>
<p>Til gengæld er disse arrays pludselig dyrere at allokere, eftersom allokering på LOH benytter en free list, hvilket kan være mange gange langsommere end den simple pointeroperation, der skal til ved allokering i generation 0. Ligeledes vil levetiden af disse arrays stige markant. Er der tale om midlertidige arrays, går de fra hurtig oprydning i generation 0 til en lang levetid på LOH. Det kan have indflydelse på hvor stor belastning garbage collection lægger på applikationen, ligesom det kan give yderligere problemer i form af fragmentering af LOH. </p>
<p>Konsekvenserne afhænger af den konkrete applikations forbrug af hukommelse, men givet er det, at det kan være en særdeles vigtig detalje i nogle scenarier. Så med mange års forsinkelse gør jeg hermed mit til at udbrede kendskabet til en godt bevaret hemmelighed. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=562</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Nyheder i C# 4 – sjette del: Bedre integration med COM</title>
		<link>http://kodehoved.dk/?p=549</link>
		<comments>http://kodehoved.dk/?p=549#comments</comments>
		<pubDate>Thu, 22 Jul 2010 17:46:31 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[.NET 4.0]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# 4.0]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=549</guid>
		<description><![CDATA[Mens vi venter på afgørelsen af kodegolfkonkurrencen (du kan stadig nå at indsende bidrag, så go go go!), fortsætter jeg min serie om nyheder i C# 4.
Som vi så på i forrige indslag i serien, har det tidligere været lidt af et helvede at kalde Microsoft Office COM objekter via C#. Dynamiske typer samt valgfri [...]]]></description>
			<content:encoded><![CDATA[<p>Mens vi venter på afgørelsen af <a href="/?p=530">kodegolfkonkurrencen</a> (du kan stadig nå at indsende bidrag, så go go go!), fortsætter jeg min serie om nyheder i C# 4.</p>
<p>Som vi så på i <a href="/?p=520">forrige indslag</a> i serien, har det tidligere været lidt af et helvede at kalde Microsoft Office COM objekter via C#. Dynamiske typer samt valgfri og navngivne parametre hjælper i den sammenhæng, men heldigvis er Microsoft gået endnu længere for at gøre kode, der arbejder mod disse grænseflader lettere at arbejde med. Udover de nævnte features tilbyder C# 4 følgende til bedre COM-integration:</p>
<ul>
<li>No-ref</li>
</ul>
<ul>
<li>Index properties</li>
</ul>
<ul>
<li>No PIA</li>
</ul>
<p>Lad os se på et eksempel. Skal vi f.eks. starte Word og åbne et nyt dokument, så koden før C# 4 ud nogenlunde som følger:</p>
<pre class="syntax-highlight:c#">
private void OpenWord() {
   // instance needed due to ref
   object missing = Type.Missing;
   object index = 1;
   var word = new Word.Application();

   word.Documents.Add(ref missing, ref missing, ref missing, ref missing);

   // pseudo index property
   Document = word.Documents.get_Item(ref index);

   word.Visible = true;
}
</pre>
<p>Læg mærke til at COM-grænsefladen kræver, at alle parametre overføres via <code>ref</code>, og derfor er vi nødt til at oprette lokale referencer – også selvom vi egentlig ikke er interesseret i at overføre en værdi i flere af tilfældene. Det betyder også, at når vi skal overføre værdien <code>1</code> til <code>get_Item()</code>, er vi nødt til at oprette en reference til en boxed <code>int</code> med værdien <code>1</code>, så vi kan overføre denne som en reference. </p>
<p>Heldigvis er der hjælp at hente i C# 4. No-ref fjerner behovet for at skrive alle de omfattende <code>ref</code>-overførelser af parametre. Selve kaldet er naturligvis ikke ændret, da grænsefladen nu engang ser ud, som den gør, men compileren sørge for at generere den nødvendige kode på baggrund af en velkendt syntaks. Ovenstående metode ser således ud som følger i C# 4.</p>
<pre class="syntax-highlight:c#">
private void OpenWord() {
   var word = new Word.Application();

   word.Documents.Add();
   Document = word.Documents[1];

   word.Visible = true;
}
</pre>
<p>Læg mærke til, at alle de kedelige <code>ref</code>-kald er væk. De overflødige parametre er ligeledes fjernet, og compileren tillader nu, at vi kan nu kalde <code>get_Item()</code>, som om det var en almindelig index property. Alt i alt får vi en syntaks for COM-interaktion, der ligner det vi er vant til fra interaktion med almindelige .NET typer.</p>
<p>Det bringer os til sidste nye feature i denne sammenhæng: No-PIA, men inden vi ser på den, er det nok på sin plads at forklare, hvad PIA er. PIA står for <em>Primary Interop Assemblies</em>, og er en betegnelse for specielle assemblies, der erklærer .NET-typedefinitioner for eksisterende COM-typer. Det er med andre ord den grænseflade, vores .NET applikation bruger til at kommunikere med COM-objekter i f.eks. Microsoft Office.</p>
<p>For at kunne tilgå de ønskede COM-objekter, er vi altså nødt til at have det eller de relevante PIAs til rådighed. Hvert PIA indeholder typedefinitioner for alle de relevante COM-typer for den givne applikation, så de kan blive ganske omfattende. Det vil sige, at selv hvis vores applikation kun har brug for en lille del af f.eks. Word eller Excel, er vi nødt til at inkludere de komplette PIAs for disse. Det kan blive et problem i visse sammenhænge.</p>
<p>Med No-PIA sørger compileren for at inkludere de nødvendige typedefinitioner i vores assembly, hvilket har to konsekvenser. For det første behøver vi ikke længere at bekymre os om distribution af PIAs og for det andet, slæber vi ikke rundt på definitioner for samtlige typer. Det gør distribution af vores applikation mere smidig. </p>
<p>I næste og sidste indlæg i denne serie skal vi se på varians. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=549</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Debugging adplus.exe</title>
		<link>http://kodehoved.dk/?p=542</link>
		<comments>http://kodehoved.dk/?p=542#comments</comments>
		<pubDate>Tue, 20 Jul 2010 11:27:30 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[WinDbg]]></category>
		<category><![CDATA[sos.dll]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=542</guid>
		<description><![CDATA[Nej, der mangler ikke et &#8220;med&#8221; i overskriften. Dette indlæg handler om en fejl, jeg fandt i ADPlus.
I den seneste version af Debugging Tools for Windows er det gamle ADPlus vb-script blevet udskiftet med en exe-fil. ADPlus er blevet genimplementeret som en managed applikation (det gamle script er stadig tilgængelig under navnet adplus_old.vbs).
Ifølge det medfølgende [...]]]></description>
			<content:encoded><![CDATA[<p>Nej, der mangler ikke et &#8220;med&#8221; i overskriften. Dette indlæg handler om en fejl, jeg fandt i ADPlus.</p>
<p>I den seneste version af Debugging Tools for Windows er det gamle ADPlus vb-script blevet udskiftet med en exe-fil. ADPlus er blevet genimplementeret som en managed applikation (det gamle script er stadig tilgængelig under navnet <code>adplus_old.vbs</code>).</p>
<p>Ifølge det medfølgende Word-dokument er dette gjort for bedre at kunne udvide ADPlus med ny funktionalitet, og der er allerede kommet et par yderligere muligheder som f.eks. <code>–pmn</code>, der overvåger alle processer med et bestemt navn.</p>
<p>Det er dog ikke det, vi skal se på i dette indlæg. Ligesom sin forgænger understøtter <code>adplus.exe</code>, at vi kan få debuggeren til at starte vores applikation via <code>–sc</code>. Desværre er denne feature ikke implementeret særlig elegant i den nye version. </p>
<p>I forbindelse med en debugging-opgave havde jeg brug for at starte min applikation via <code>–sc</code>, men uanset hvad jeg gjorde, fik jeg nedenstående fejlmeddelelse: </p>
<pre class="syntax-highlight:sh">
Spawning c:\dev2010\testapp\testapp\bin\release\testapp.exe
!!! ERROR !!!
The system cannot find the file specified
   at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
   at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
   at ADPlus.AdplusEngine.SpawnProcess(String SpawnCommand)
   at ADPlus.AdplusApl.TryAttachSelectedProcesses()
   at ADPlus.AdplusApl.TryRun()
!!!ERROR - ADPlus failed to run
</pre>
<p>Det fik mig til at tro, at ADPlus af en eller anden grund ikke kunne finde min applikation, men det er faktisk ikke det, fejlmeddelelsen angiver.</p>
<p>I mangel på bedre fyrede jeg op under WinDbg for at finde ud af, hvorfor denne fejl opstod. </p>
<p><code>adplus.exe</code> er som sagt en managed applikation, og den er bygget til CLR version 2 og AnyCPU, så vores runtime hedder <code>mscorwks</code>, og vi skal have fat i 64 bit versionen af WinDbg på trods af, at vi ønsker at debugge den version, der kommer med 32 bit versionen af Debugging Tools for Windows. </p>
<p>Via Open Executable-dialogen kan vi udvælge adplus.exe og angive de relevante opstartsparametre. Herefter starter WinDbg <code>adplus.exe</code>, men stopper udførelsen, så snart processen er i luften. På dette tidspunkt er CLRen ikke startet endnu, så vi får ikke noget ud af at forsøge at indlæse SOS. I stedet kan vi sætte et event filter så eksekveringen stopper, når CLRen indlæses og derefter indlæse SOS. Det kan gøres som følger:</p>
<pre class="syntax-highlight:sh">
sxe -c &quot;.loadby sos mscorwks&quot; ld mscorwks
</pre>
<p>Herefter kører vi videre, indtil vi rammer vores event filter og får indlæst SOS.</p>
<pre class="syntax-highlight:sh">
0:000&gt; g
ModLoad: 000007fe`efd10000 000007fe`f06be000   C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscorwks.dll
ntdll!ZwMapViewOfSection+0xa:
00000000`77b9ffda c3              ret
</pre>
<p>Vi ved fra fejludskriften, at der bliver smidt en exception, så lad os sætte et event filter for managed exceptions. </p>
<pre class="syntax-highlight:sh">
0:000&gt; sxe -c &quot;!clrstack; !pe&quot; clr
</pre>
<p>Ovenstående stopper i tilfælde af en managed exception og udskriver derefter kaldestak for den aktuelle tråd samt detaljerne om vores exception. Og så kører vi igen:</p>
<pre class="syntax-highlight:sh">
0:000&gt; g
(14c4.13fc): CLR exception - code e0434f4d (first chance)
OS Thread Id: 0x13fc (0)
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_64\System\247913fa7ae6fcf04ea33d28d24ab611\System.ni.dll
Child-SP         RetAddr          Call Site
00000000002eec30 000007feefa406bc System.Diagnostics.Process.StartWithShellExecuteEx(System.Diagnostics.ProcessStartInfo)
00000000002eed30 000007ff00198597 System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo)
00000000002eed70 000007ff00197ef0 ADPlus.AdplusEngine.SpawnProcess(System.String)
00000000002eedc0 000007ff001942ce ADPlus.AdplusApl.TryAttachSelectedProcesses()
00000000002eee50 000007ff00191d98 ADPlus.AdplusApl.TryRun()
00000000002eeec0 000007ff0019026e ADPlus.AdplusApl.TryExecute(System.String[])
00000000002eef00 000007feeffdd502 ADPlus.Program.Main(System.String[])
Exception object: 000000000265fe10
Exception type: System.ComponentModel.Win32Exception
Message: The system cannot find the file specified
InnerException: &lt;none&gt;
StackTrace (generated):
&lt;none&gt;
StackTraceString: &lt;none&gt;
HResult: 80004005
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
KERNELBASE!RaiseException+0x39:
000007fe`fdb6aa7d 4881c4c8000000  add     rsp,0C8h
</pre>
<p>Debuggeren er stoppet som følge af en exception. Det ser ud til at passe meget godt med vores fejlsituation, så nu skal vi blot finde ud af, hvad det er for en fil, der ikke kan lokaliseres (tænk på hvor meget lettere alt ville være, hvis vi bare kunne læse det ud af vores exception). </p>
<p>Via kaldestakken kan vi se, at <code>StartWithShellExecuteEx</code> bliver kaldt med en instans af <code>ProcessStartInfo</code>. Hvis vi er heldige, er der en reference til denne på stakken. På 64 bit Windows overføres de fire første argumenter altid i registre, så vi kan ikke regne med at finde noget på stakken. I visse situationen opretter compileren dog lokale referencer på stakken, så det er vores første forsøg:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !dso
OS Thread Id: 0x13fc (0)
RSP/REG          Object           Name
00000000002eea30 000000000265fef8 System.Text.StringBuilder
00000000002eea68 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eea70 00000000025a7b48 System.String
00000000002eea80 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eeaa0 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eeaf0 000000000265ff20 System.String
00000000002eeb00 0000000002660140 System.String
00000000002eeb70 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eeb78 00000000025a7b48 System.String
00000000002eeb80 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eebd8 00000000025a7b48 System.String
00000000002eebe0 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eec10 000000000265fdf0 System.Diagnostics.ShellExecuteHelper
00000000002eec20 000000000265fe10 System.ComponentModel.Win32Exception
00000000002eec60 000000000265fbb8 System.Diagnostics.Process
00000000002eec68 00000000025a7b48 System.String
00000000002eec70 000000000265f238 System.Diagnostics.ProcessStartInfo
00000000002eece0 000000000265fcc8 Microsoft.Win32.NativeMethods+ShellExecuteInfo
00000000002eed10 000000000265f238 System.Diagnostics.ProcessStartInfo
00000000002eed18 00000000025a7a98 ADPlus.AdplusEngine
00000000002eed20 000000000265fbb8 System.Diagnostics.Process
00000000002eed30 000000000265fbb8 System.Diagnostics.Process
00000000002eed38 000000000265f238 System.Diagnostics.ProcessStartInfo
00000000002eed50 00000000025a7b48 System.String
00000000002eed58 000000000265f238 System.Diagnostics.ProcessStartInfo
00000000002eed60 000000000265f130 System.String
...
</pre>
<p>Jeg har forkortet listen en smule, men som vi kan se, er der faktisk en reference til en instans af <code>ProcessStartInfo</code>. Heldigt, så behøver vi ikke grave videre. Lad os se nærmere på instansen.</p>
<pre class="syntax-highlight:sh">
0:000&gt; !do 000000000265f238
Name: System.Diagnostics.ProcessStartInfo
MethodTable: 000007feefb3ce18
EEClass: 000007feef39dcb8
Size: 128(0x80) bytes
 (C:\Windows\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feee37ec90  4003376        8        System.String  0 instance 00000000025a7b48 fileName
000007feee37ec90  4003377       10        System.String  0 instance 000000000265f130 arguments
000007feee37ec90  4003378       18        System.String  0 instance 0000000000000000 directory
000007feee37ec90  4003379       20        System.String  0 instance 0000000000000000 verb
000007feefb0ace0  400337a       68         System.Int32  1 instance                2 windowStyle
000007feee37de60  400337b       6c       System.Boolean  1 instance                0 errorDialog
000007feee381698  400337c       60        System.IntPtr  1 instance                0 errorDialogParentHandle
000007feee37de60  400337d       6d       System.Boolean  1 instance                1 useShellExecute
000007feee37ec90  400337e       28        System.String  0 instance 0000000000000000 userName
000007feee37ec90  400337f       30        System.String  0 instance 0000000000000000 domain
000007feeeb78b50  4003380       38 ...rity.SecureString  0 instance 0000000000000000 password
000007feee37de60  4003381       6e       System.Boolean  1 instance                0 loadUserProfile
000007feee37de60  4003382       6f       System.Boolean  1 instance                0 redirectStandardInput
000007feee37de60  4003383       70       System.Boolean  1 instance                0 redirectStandardOutput
000007feee37de60  4003384       71       System.Boolean  1 instance                0 redirectStandardError
000007feee386ae0  4003385       40 System.Text.Encoding  0 instance 0000000000000000 standardOutputEncoding
000007feee386ae0  4003386       48 System.Text.Encoding  0 instance 0000000000000000 standardErrorEncoding
000007feee37de60  4003387       72       System.Boolean  1 instance                0 createNoWindow
000007feee377a90  4003388       50 System.WeakReference  0 instance 0000000000000000 weakParentProcess
000007feef5d5d68  4003389       58 ....StringDictionary  0 instance 0000000000000000 environmentVariables
</pre>
<p>Læg mærke til det første felt ved navn <code>fileName</code>. Det må vi hellere se nærmere på:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !do 00000000025a7b48
Name: System.String
MethodTable: 000007feee37ec90
EEClass: 000007feedf8b038
Size: 40(0x28) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: cdb.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feee385f00  4000096        8         System.Int32  1 instance                8 m_arrayLength
000007feee385f00  4000097        c         System.Int32  1 instance                7 m_stringLength
000007feee3806d8  4000098       10          System.Char  1 instance               63 m_firstChar
000007feee37ec90  4000099       20        System.String  0   shared           static Empty
                                 &gt;&gt; Domain:Value  00000000003d0390:00000000025a1308 &lt;&lt;
000007feee380588  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                 &gt;&gt; Domain:Value  00000000003d0390:00000000025a1a38 &lt;&lt;
</pre>
<p>Hmm, det indeholder <code>cdb.exe</code>. Så det er altså der, skoen trykker. Det er ikke fordi <code>adplus.exe</code> ikke kan finde min applikation, men fordi den ikke kan finde <code>cdb.exe</code>. </p>
<p>Det er jo underligt, for de andre kommandoer har ingen problemer med at finde <code>cdb.exe</code>. Det betyder selvfølgelig, at vi kan løse problemet ved blot at tilføje det relevante directory til vores path, men nu er der faktisk en grund til, at jeg ikke har Debugging Tools for Windows i min path. Jeg har tre versioner installeret (nyeste version i 32 og 64 bit samt en 32 bit udgave af 6.7.5), og jeg vil selv kunne bestemme hvilken en jeg får fat i, og derfor har jeg ingen af disse i min path.  </p>
<p>Det oplagte spørgsmål er: Hvorfor fejler <code>–sc</code>, når de andre kommandoer virker uden path? Kaldestakken fortæller os, at den relevante metode i ADPlus er <code>SpawnProcess</code>. Denne metode viser sig at være en instansmetode på typen <code>AdplusEngine</code> – <code>adplus.exe</code> er jo en managed applikation, så vi kan inspicere koden ved hjælp af Reflector. </p>
<p>Hvis vi kan kalde <code>SpawnProcess</code>, må der være en instans af <code>AdplusEngine</code> på heapen. Går vi tilbage til ovenstående liste af stakreferencer, finder vi faktisk en reference til en sådan instans. Lad os se nærmere på den.</p>
<pre class="syntax-highlight:sh">
0:000&gt; !do 00000000025a7a98
Name: ADPlus.AdplusEngine
MethodTable: 000007ff00054068
EEClass: 000007ff00182688
Size: 176(0xb0) bytes
 (C:\dbg32\adplus.exe)
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
0000000000000000  4000009        8                       0 instance 00000000025ab618 m_KeyWords
0000000000000000  400000a       10                       0 instance 00000000025ab500 m_KeyWordsCustom
0000000000000000  400000b       18                       0 instance 00000000025ac580 m_Exceptions
0000000000000000  400000c       20                       0 instance 00000000025ae0f0 m_Breakpoints
000007feee37ec90  400000d       28        System.String  0 instance 00000000025a8c90 m_HangConfiguration
000007feee37de60  400000e       9c       System.Boolean  1 instance                0 m_HangConfigurationChanged
0000000000000000  400000f       30                       0 instance 00000000025ae080 m_PreCommands
0000000000000000  4000010       38                       0 instance 00000000025ae0c8 m_PostCommands
0000000000000000  4000011       40                       0 instance 00000000025ae138 m_NotilyList
000007feee37ec90  4000012       48        System.String  0 instance 00000000025a32a8 m_OutputDir
000007feee37ec90  4000013       50        System.String  0 instance 00000000025b1680 m_OutputDumpDir
000007ff00053f10  4000014       98         System.Int32  1 instance                1 m_RunMode
000007feee37ec90  4000015       58        System.String  0 instance 00000000025ad9a0 m_DateTimeStamp
000007feee37ec90  4000016       60        System.String  0 instance 00000000025a1308 m_Sympath
000007feee37de60  4000017       9d       System.Boolean  1 instance                1 m_SympathSet
000007feee37ec90  4000018       68        System.String  0 instance 00000000025a1308 m_MssLocalCache
000007feee37de60  4000019       9e       System.Boolean  1 instance                0 m_AddMss
000007feee37ec90  400001a       70        System.String  0 instance 00000000025a1308 m_LastScriptCommand
000007feee37ec90  400001b       78        System.String  0 instance 00000000025a7b48 m_Debugger
000007feee37de60  400001c       9f       System.Boolean  1 instance                0 m_ExtensionInteraction
000007feee37de60  400001d       a0       System.Boolean  1 instance                0 m_ExtensionDebug
000007feee37ec90  400001e       80        System.String  0 instance 00000000025ab408 m_AdplusPath
000007feee37ec90  400001f       88        System.String  0 instance 00000000025a1308 m_DebuggersPath
000007ff00053808  4000020       90     ADPlus.AdplusApl  0 instance 00000000025a77c0 m_AdplusApl
000007feee37ec90  4000005        8        System.String  0   static 00000000025a6af0 m_Version
000007feee37ec90  4000006       10        System.String  0   static 00000000025a6b20 m_VersionDate
000007feee374748  4000007       18      System.Object[]  0   static 00000000025a6b90 m_LineSeparator
000007feee374748  4000008       20      System.Object[]  0   static 00000000025a6bb8 m_KWSeparator
</pre>
<p>Læg mærke til <code>m_AdplusPath</code>. Lad os se, hvad den indeholder.</p>
<pre class="syntax-highlight:sh">
0:000&gt; !do 00000000025ab408
Name: System.String
MethodTable: 000007feee37ec90
EEClass: 000007feedf8b038
Size: 44(0x2c) bytes
 (C:\Windows\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: C:\dbg32\
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feee385f00  4000096        8         System.Int32  1 instance               10 m_arrayLength
000007feee385f00  4000097        c         System.Int32  1 instance                9 m_stringLength
000007feee3806d8  4000098       10          System.Char  1 instance               43 m_firstChar
000007feee37ec90  4000099       20        System.String  0   shared           static Empty
                                 &gt;&gt; Domain:Value  00000000003d0390:00000000025a1308 &lt;&lt;
000007feee380588  400009a       28        System.Char[]  0   shared           static WhitespaceChars
                                 &gt;&gt; Domain:Value  00000000003d0390:00000000025a1a38 &lt;&lt;
</pre>
<p>Den indeholder <code>c:\dbg32</code>, som er en junction til min 32 bit installation af Debugging Tools for Windows. </p>
<p>ADPlus har altså de nødvendige oplysninger til rådighed, men glemmer åbenbart at bruge dem. Lad os se på implementeringen af <code>SpawnProcess</code>:</p>
<pre class="syntax-highlight:c#">
public void SpawnProcess(string SpawnCommand)
{
   Logger.LogAndOut(&quot;Spawning &quot; + SpawnCommand);
   string debugger = this.m_Debugger;
   string arguments = (&quot;-c $&lt;\&quot;&quot; + this.OutputDumpDir + &quot;\\DebuggerScript.txt\&quot; &quot;) + SpawnCommand;
   Process.Start(new ProcessStartInfo(debugger, arguments) { WindowStyle = ProcessWindowStyle.Minimized });
}
</pre>
<p><code>ProcessStartInfo</code> oprettes blot med indholdet af <code>m_Debugger</code>, og får således ikke <code>m_AdplusPath</code> med, og der har vi altså problemet. </p>
<p>Nu skal jeg bare vente på, at Microsoft får rettet fejlen.</p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=542</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kodegolf: Vind Visual Studio 2010 Ultimate</title>
		<link>http://kodehoved.dk/?p=530</link>
		<comments>http://kodehoved.dk/?p=530#comments</comments>
		<pubDate>Wed, 14 Jul 2010 08:02:32 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[For sjov]]></category>
		<category><![CDATA[kodehoved.dk]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=530</guid>
		<description><![CDATA[Det er sommer, det er varmt, og det er tid til en gang golf. Her på siden foregår den slags jo ikke ude i det fri men derimod foran computeren, hvilket sikkert ikke er det værste sted at opholde sig i disse høj-UV-tider.
Denne gang går opgaven ud på at implementere nedenstående metode, der kan lægge [...]]]></description>
			<content:encoded><![CDATA[<p>Det er sommer, det er varmt, og det er tid til en gang golf. Her på siden foregår den slags jo ikke ude i det fri men derimod foran computeren, hvilket sikkert ikke er det værste sted at opholde sig i disse høj-UV-tider.</p>
<p>Denne gang går opgaven ud på at implementere nedenstående metode, der kan lægge potentielt meget store, ikke-negative heltal sammen. Koden skal skrives i C#.</p>
<pre class="syntax-highlight:c#">
public static int[] Add(int[] a, int[] b) { }
</pre>
<p>Som det fremgår, tager <code>Add()</code> to <code>int[]</code>. Hvert <code>int</code> i de to arrays repræsenterer et ciffer, så hvis <code>a</code> repræsenterer værdien 1000, indeholder den <code>{ 1, 0, 0, 0 }</code>, og hvis <code>b</code> rummer værdien på <code>Decimal.MaxValue</code> indeholder den <code>{ 7, 9, 2, 2, 8, 1, 6, 2, 5, 1, 4, 2, 6, 4, 3, 3, 7, 5, 9, 3, 5, 4, 3, 9, 5, 0, 3, 3, 5 }</code>. Den øvre grænse for tallenes størrelse er kun begrænset af størrelsen på <code>int[]</code>. De to værdier skal lægges sammen og returneres som <code>int[]</code>.</p>
<p>Følgende regler gælder:</p>
<ul>
<li>Alle anslag mellem metodedefinitionens start- og slut-curlies tælles med – white space, der ikke har betydning for metodens virke er dog undtaget. </li>
</ul>
<ul>
<li><code>a</code> og <code>b</code> kan ikke være tomme, men de har ikke nødvendigvis samme længde.</li>
</ul>
<ul>
<li>Alle regneoperationer skal foregå på datatypen <code>int</code>. </li>
</ul>
<ul>
<li>Det er ikke tilladt at bruge <code>BigInteger</code>.</li>
</ul>
<ul>
<li>Alle udregninger skal foregå i <code>Add()</code>.</li>
</ul>
<ul>
<li>Ingen hjemmelavede hjælpemetoder eller erklæringer uden for <code>Add()</code>.</li>
</ul>
<ul>
<li>Navngiv metoden så den hedder <code>DitNavnEllerAlias_Add</code>, f.eks. kunne min version hedde <code>Kodehoved_Add</code>. Navnets længde påvirker ikke optællingen med mindre metoden benytter rekursion (så lad være med det).</li>
</ul>
<ul>
<li>Det er ikke tilladt at bruge <code>using</code>-aliaser, da alle bidrag bliver testet af samme program.</li>
</ul>
<ul>
<li>Resultatet må ikke indeholde foranstillede nuller.</li>
</ul>
<ul>
<li>Send løsningsforslag til brian@kodehoved.dk.</li>
</ul>
<ul>
<li><strong>Deadline</strong>: 30. juli kl. 20.00.</li>
</ul>
<p>Jeg har et stk. <strong>Microsoft Visual Studio 2010 Ultimate with MSDN</strong> som præmie. Vinderen er den, der leverer en korrekt løsning på ovenstående med færrest mulige anslag. I tilfælde af flere løsninger med lige få anslag trækker jeg lod blandt disse. </p>
<p>Skulle der være uklarheder så skriv en kommentar, så skal jeg uddybe snarest. Følg med i kommentarerne og husk at tjekke for opdateringer til dette indlæg. God fornøjelse!</p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=530</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Nyheder i C# 4 – femte del: Valgfri og navngivne parametre</title>
		<link>http://kodehoved.dk/?p=520</link>
		<comments>http://kodehoved.dk/?p=520#comments</comments>
		<pubDate>Tue, 06 Jul 2010 17:25:30 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# 4.0]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=520</guid>
		<description><![CDATA[Dette er femte indlæg i min serie om nyheder i C# 4. Efter at vi har set på dynamiske typer, er tiden kommet til valgfri og navngivne parametre. 
Kort fortalt er effekten af disse to features, at vi kan undlade og/eller ændre på rækkefølgen af parametre, når vi kalder en metode. I en ideel verden [...]]]></description>
			<content:encoded><![CDATA[<p>Dette er femte indlæg i min serie om nyheder i C# 4. Efter at <a href="/?p=453">vi har set på dynamiske typer</a>, er tiden kommet til valgfri og navngivne parametre. </p>
<p>Kort fortalt er effekten af disse to features, at vi kan undlade og/eller ændre på rækkefølgen af parametre, når vi kalder en metode. I en ideel verden hvor alle metoder har de og kun de parametre, de har brug for, er det måske ikke en særlig nyttig egenskab, men hvis man nogensinde har set Microsoft Offices COM interface, ved man, at det ikke er en ideel verden. Lad mig illustrere:</p>
<pre class="syntax-highlight:c#">
word.Documents.Open(ref fileName,
   ref missingValue, ref readOnlyValue,
   ref missingValue, ref missingValue,
   ref missingValue, ref missingValue,
   ref missingValue, ref missingValue,
   ref missingValue, ref missingValue,
   ref missingValue, ref missingValue,
   ref missingValue, ref missingValue);
</pre>
<p>Femten parametre skal der til at åbne et dokument i Word via COM. Femten! </p>
<p>I langt de fleste tilfælde har vi kun lyst til at angive et, nemlig filnavnet, men før C# 4 var vi nødsaget til at kalde metoden med alle femten parametre. At APIet desuden kræver at alt overføres som <code>ref</code>, gør kun problemet endnu mere udtalt (heldigvis er der også forbedringer på dette punkt, som vi skal se på i efterfølgende indlæg). </p>
<p>Med de nye tiltag i C# 4 ser ovenstående kald ud som følger:</p>
<pre class="syntax-highlight:c#">
word.Documents.Open(&quot;demo.docx&quot;, ReadOnly: true);
</pre>
<p>Meget bedre! Første parameter overføres via sin position, mens tredje parameter overføres ved sit navn. Det tillader os at springe parameter nummer to over. Derudover springer vi også alle de efterfølgende valgfri parametre over. Alt i alt giver det os en syntaks, der er langt mere læse- og skrivevenlig. </p>
<p>Lad os se på et par yderligere eksempler. Betragt nedenstående metode:</p>
<pre class="syntax-highlight:c#">
public static void ListFilm(string title, int releaseYear = 2010, float score = 0f) {
   Console.WriteLine(&quot;{0} ({1}): {2}&quot;, title, releaseYear, score);
}
</pre>
<p>Ovenstående erklærer en metode med tre parametre: <code>title</code> er obligatorisk, mens <code>releaseYear</code> og <code>score</code> er valgfri. Vi kan altså kalde metoden på forskellig vis, f.eks.:</p>
<pre class="syntax-highlight:c#">
ListFilm(&quot;Delicatessen&quot;, 1991, 7.9f);

// dårlig film, score er 0
ListFilm(&quot;Lara Croft: Tomb Raider&quot;, 2001); 

// udkommer i 2010 og vi regner med, at det er en god film
ListFilm(&quot;Les aventures extraordinaires d'Adèle Blanc-Sec&quot;, score: 8.0f);
</pre>
<p>Som det fremgår, kan vi kalde metoden afhængig af, hvor mange parametre vi kommer med. Hvis alle parametrene er navngivne, kan vi se helt bort fra rækkefølgen, men almindeligvis vil vi nok have et eller få obligatoriske parametre samt et par valgfri, så en blanding vil nok være det hyppigst forekomne. </p>
<p>Fælles for navngivne og valgfri parametre er, at der er tale om en compiler-feature. Al håndtering sker således på oversættelsestidspunktet, og der er ikke spor af hverken navngivne eller valgfri parametre på afviklingstidspunktet. </p>
<p>For valgfri parametre indsætter compileren simpelthen de konkrete standardværdier ved oversættelse af metodekaldet. </p>
<p>For navngivne parametre bruges navnene til at identificere de korrekte placeringer for parametrene, og derefter genereres metodekald på almindeligvis. </p>
<p>Der er selvfølgelig den detalje, at såvel standardværdier som navne bliver en del af metodens signatur på oversættelsestidspunktet, så ændringer af disse slår kun igennem ved genoversættelse. Assemblies, der ikke genoversættes, vil have tidligere standardværdier indlejret i koden. Dette er kun et problem, hvis assemblies oversættes og distribueres særskilt. </p>
<p>Valgfri og navngivne parametre er måske ikke et revolutionerende tiltag, men det er en god, lille forbedring, der i visse situationer kan bidrage væsentlig til læsbarheden af kode. Brug dem hvor det giver mening. </p>
<p>I næste indlæg ser vi mere på forbedringerne omkring integration med COM.</p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=520</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Justering af referencer i ubrugte objekter</title>
		<link>http://kodehoved.dk/?p=501</link>
		<comments>http://kodehoved.dk/?p=501#comments</comments>
		<pubDate>Mon, 05 Jul 2010 17:18:04 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Garbage Collection]]></category>
		<category><![CDATA[WinDbg]]></category>
		<category><![CDATA[sos.dll]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=501</guid>
		<description><![CDATA[Dette indlæg omhandler forholdsvis eksotiske detaljer omkring implementeringen af garbage collection i .NET. Det vil næppe være relevant i ret mange tilfælde, men at kortlægge disse detaljer var en underholdende og lærerig øvelse, så dette indlæg er i realiteten mere et vidnesbyrd om, hvad vi kan lære om .NETs afviklingsmiljø ved hjælp af WinDbg og [...]]]></description>
			<content:encoded><![CDATA[<p>Dette indlæg omhandler forholdsvis eksotiske detaljer omkring implementeringen af garbage collection i .NET. Det vil næppe være relevant i ret mange tilfælde, men at kortlægge disse detaljer var en underholdende og lærerig øvelse, så dette indlæg er i realiteten mere et vidnesbyrd om, hvad vi kan lære om .NETs afviklingsmiljø ved hjælp af WinDbg og SOS. </p>
<p>En kollega kom for nogle dage siden forbi og spurgte, om jeg vidste noget om en funktion ved navn <code>gc_heap::relocate_in_large_objects</code>. Det gjorde jeg tilfældigvis, for jeg var selv stødt på denne lidt spøjst navngivne funktion i anden sammenhæng. Navnet kan jo få en til at tro, at objekter på <em>Large Object Heap</em> (LOH) bliver flyttet, hvilket jo som bekendt ikke er tilfældet. Funktionen står derimod for at justere referencer i objekter på LOH. </p>
<p>Betragt nedenstående figur.</p>
<p><img alt="LOH før garbage collection og compaction" src="/images/loh-before.png" width="440" height="262" /></p>
<p>Her har vi et array på LOH med referencer til objekter på den almindelige heap. Oprydning af sidstnævnte kan føre til at objekterne bliver rykket sammen for at forhindre fragmentering. Hvis dette sker, skal referencerne i vores array justeres, så de igen peger på de faktiske instanser. Efter en oprydning, sammenrykning og justering kan billedet se ud som følger:</p>
<p><img alt="LOH efter garbage collection og compaction" src="/images/loh-after.png" width="440" height="262" /></p>
<p>Det er der næppe noget nyt eller overraskende i, men min kollega synes at have observeret, at justering af referencer også skete, hvis den omtalte array ikke længere var i brug. </p>
<p>Kunne det være tilfældet? </p>
<p>Tænk lidt over det: Bliver referencer virkelig justeret for objekter, der ikke længere er i brug af applikationen?</p>
<p>Mit første svar var forkert. Jeg var overbevist om, at der ikke var nogen grund til at justere disse referencer i fald vores array ikke længere var i brug, men i stedet for at lade det komme an på, hvad jeg troede, satte jeg mig for at undersøge det.</p>
<p>Til formålet lavede jeg en lille testapplikation som angivet nedenfor:</p>
<pre class="syntax-highlight:c#">
sealed class SomeType {
   public int X { get; set; }
   public int Y { get; set; }

   public SomeType(int x, int y) {
      X = x;
      Y = y;
   }
}

sealed class Program {
   static void GenerateRandomObjects() {
      string s = null;
      for (int i = 0; i &lt; 1000; i++) {
         s += i.ToString();
      }
      Console.WriteLine(s.Length);
   }

   static void Main() {
      Console.WriteLine(&quot;Press Enter to begin&quot;);
      Console.ReadLine();

      GenerateRandomObjects();
      var smallbuffer = new SomeType[100];
      var largebuffer = new SomeType[85000];

      for (int i = 0; i &lt; smallbuffer.Length; i++) {
         var st = new SomeType(1, 2);
         smallbuffer[i] = st;
         largebuffer[i] = st;
      }

      Trace.WriteLine(&quot;Buffers filled&quot;);
      Debugger.Break();

      Trace.WriteLine(string.Format(&quot;smallbuffer is in gen{0}&quot;, GC.GetGeneration(smallbuffer)));

      Trace.WriteLine(&quot;Nulling root to largebuffer&quot;);
      largebuffer = new SomeType[200];
      Debugger.Break();

      Trace.WriteLine(string.Format(&quot;smallbuffer is in gen{0}&quot;, GC.GetGeneration(smallbuffer)));

      Trace.WriteLine(&quot;Collecting ...&quot;);
      GC.Collect(1);
      Trace.WriteLine(string.Format(&quot;smallbuffer is in gen{0}&quot;, GC.GetGeneration(smallbuffer)));
      GenerateRandomObjects();

      Trace.WriteLine(&quot;After GC&quot;);
      Debugger.Break();

      Console.WriteLine(smallbuffer.Length);
      Console.WriteLine(largebuffer.Length);
   }
}
</pre>
<p>Applikationen gør som følger:</p>
<ul>
<li>Først opretter den et array, der er stort nok til, at det ryger på LOH.</li>
</ul>
<ul>
<li>Dette array sættes til at pege på et antal objekter allokeret på den almindelige heap. For at gøre det lettere at spore disse objekter, lader jeg også et mindre array referere disse.
</li>
</ul>
<ul>
<li>Det næste skridt er, at sørge for at det store array ikke længere er refereret. Det er ikke helt så let, som det lyder. Det er ofte utilstrækkeligt at sætte den lokale reference til <code>null</code>. I mange tilfælde vil vi nemlig stadig have en gyldig reference på stakken eller i et register. Derfor er den bedste fremgangsmåde, at lade referencen pege på en ny instans. Det sikrer, at vi få overskrevet eventuelle gemte referencer.
</li>
</ul>
<ul>
<li>Dernæst skal jeg iværksætte en garbage collection, der også laver compaction, så objekterne bliver flyttet på heapen. Dette er også mere tricky end som så, da vi ikke har mulighed for at angive, at der skal foretages compaction ved kald til <code>GC.Collect()</code>. Ergo, var jeg nødt til at prøve mig frem. Ved at lave en del tilfældige objekter rundt om mit lille array (og de refererede objekter) og derefter lave et kald til <code>GC.Collect(1)</code>, fik jeg sat gang i den nødvendige oprydning. Så langt så godt.</li>
</ul>
<p>For at undersøge om referencerne faktisk blev justeret i det store array, gjorde jeg følgende:</p>
<p>Ved første break brugte jeg <code>!dumpheap</code> til at finde mine arrays. Det mindste array har plads til 100 referencer, så jeg filtrerede listen, så jeg kun fik instanser på mere end 400 bytes.</p>
<pre class="syntax-highlight:sh">
0:004&gt; g
Buffers filled
(1bdc.1918): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0000a020 edx=0030f230 esi=00687048 edi=00000064
eip=761d22a1 esp=0030f1a0 ebp=0030f23c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
KERNELBASE!DebugBreak+0x2:
761d22a1 cc              int     3
0:000&gt; !dumpheap -type Object[] -min 400
 Address       MT     Size
02427060 64cf6c28     8208
026dfc7c 64cf6c28      416
026f9758 64cf6c28      528
03421010 64cf6c28     4096
03422020 64cf6c28      528
03422240 64cf6c28     4096
03423250 64cf6c28     8176
03425250 64cf6c28   340016
total 0 objects
Statistics:
      MT    Count    TotalSize Class Name
64cf6c28        8       366064 System.Object[]
Total 8 objects
</pre>
<p>De to interessante instanser var henholdsvis <code>026dfc7c</code> (<code>smallbuffer</code>) og <code>03425250</code> (<code>largebuffer</code>).</p>
<p>For at verificere, at de begge pegede på samme elementer, udskrev jeg første element i hver array.</p>
<p>Først <code>smallbuffer</code>:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !da -details -length 1 026dfc7c
Name:        LOHRoots.SomeType[]
MethodTable: 64cf6c28
EEClass:     64a79698
Size:        416(0x1a0) bytes
Array:       Rank 1, Number of elements 100, Type CLASS
Element Methodtable: 001638cc
[0] 026dfe1c
    Name:        LOHRoots.SomeType
    MethodTable: 001638cc
    EEClass:     001614e4
    Size:        16(0x10) bytes
    File:        C:\dev2010\LOHRoots\LOHRoots\bin\Release\LOHRoots.exe
    Fields:
              MT    Field   Offset                 Type VT     Attr    Value Name
        64d42978  4000001        4             System.Int32      1     instance            1     &lt;X&gt;k__BackingField
        64d42978  4000002        8             System.Int32      1     instance            2     &lt;Y&gt;k__BackingField
</pre>
<p>Og derefter <code>largebuffer</code>:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !da -details -length 1 03425250
Name:        LOHRoots.SomeType[]
MethodTable: 64cf6c28
EEClass:     64a79698
Size:        340016(0x53030) bytes
Array:       Rank 1, Number of elements 85000, Type CLASS
Element Methodtable: 001638cc
[0] 026dfe1c
    Name:        LOHRoots.SomeType
    MethodTable: 001638cc
    EEClass:     001614e4
    Size:        16(0x10) bytes
    File:        C:\dev2010\LOHRoots\LOHRoots\bin\Release\LOHRoots.exe
    Fields:
              MT    Field   Offset                 Type VT     Attr    Value Name
        64d42978  4000001        4             System.Int32      1     instance            1     &lt;X&gt;k__BackingField
        64d42978  4000002        8             System.Int32      1     instance            2     &lt;Y&gt;k__BackingField
</pre>
<p>Læg mærke til, at begge elementer peger på <code>026dfe1c</code>. Så langt så godt.</p>
<p>Herefter kørte jeg videre til det punkt, hvor referencen til <code>largebuffer</code> overskrives:</p>
<pre class="syntax-highlight:sh">
0:000&gt; g
smallbuffer is in gen0
Nulling root to largebuffer
(1bdc.1918): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0000a020 edx=0030f230 esi=00687048 edi=0242b3f8
eip=761d22a1 esp=0030f1a0 ebp=0030f23c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
KERNELBASE!DebugBreak+0x2:
761d22a1 cc              int     3
</pre>
<p>Herefter verificerede jeg, at applikationen ikke længere havde roots til <code>largebuffer</code>. </p>
<pre class="syntax-highlight:sh">
0:000&gt; !gcroot 03425250
Note: Roots found on stacks may be false positives. Run &quot;!help gcroot&quot; for
more info.
Scan Thread 0 OSTHread 1918
Scan Thread 2 OSTHread 1d34
</pre>
<p>Ingen roots, så den instans <code>largebuffer</code> peger på, kan ryddes op på dette tidspunkt. Videre til næste stop.</p>
<pre class="syntax-highlight:sh">
0:000&gt; g
smallbuffer is in gen0
Collecting ...
smallbuffer is in gen1
After GC
(1bdc.1918): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0000a020 edx=0030f230 esi=00687048 edi=0242865c
eip=761d22a1 esp=0030f1a0 ebp=0030f23c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
KERNELBASE!DebugBreak+0x2:
761d22a1 cc              int     3
</pre>
<p>På dette tidspunkt har der netop været en garbage collection. Vi ved endnu ikke, om der også har været compaction. For at undersøge dette kan vi se, om vores arrays er blevet flyttet. </p>
<pre class="syntax-highlight:sh">
0:000&gt; !dumpheap -type Object[] -min 400
 Address       MT     Size
0242566c 64cf6c28     8208
0242a3d0 64cf6c28      416
0243fb64 64cf6c28      816
03421010 64cf6c28     4096
03422020 64cf6c28      528
03422240 64cf6c28     4096
03423250 64cf6c28     8176
03425250 64cf6c28   340016
total 0 objects
Statistics:
      MT    Count    TotalSize Class Name
64cf6c28        8       366352 System.Object[]
Total 8 objects
</pre>
<p>Læg mærke til, at vores lille array er flyttet fra <code>026dfc7c</code> til <code>0242a3d0</code>, mens vores store array stadig befinder sig på <code>03425250</code>. Der har altså været compaction i forbindelse med denne garbage collection. </p>
<p>Det interessante er således at finde ud af, om referencerne i vores store (og ubrugte) array er blevet justeret.  Lad os se på det lille array:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !da -details -length 1 0242a3d0
Name:        LOHRoots.SomeType[]
MethodTable: 64cf6c28
EEClass:     64a79698
Size:        416(0x1a0) bytes
Array:       Rank 1, Number of elements 100, Type CLASS
Element Methodtable: 001638cc
[0] 0242a570
    Name:        LOHRoots.SomeType
    MethodTable: 001638cc
    EEClass:     001614e4
    Size:        16(0x10) bytes
    File:        C:\dev2010\LOHRoots\LOHRoots\bin\Release\LOHRoots.exe
    Fields:
              MT    Field   Offset                 Type VT     Attr    Value Name
        64d42978  4000001        4             System.Int32      1     instance            1     &lt;X&gt;k__BackingField
        64d42978  4000002        8             System.Int32      1     instance            2     &lt;Y&gt;k__BackingField
</pre>
<p>Og derefter det store:</p>
<pre class="syntax-highlight:sh">
0:000&gt; !da -details -length 1 03425250
Name:        LOHRoots.SomeType[]
MethodTable: 64cf6c28
EEClass:     64a79698
Size:        340016(0x53030) bytes
Array:       Rank 1, Number of elements 85000, Type CLASS
Element Methodtable: 001638cc
[0] 0242a570
    Name:        LOHRoots.SomeType
    MethodTable: 001638cc
    EEClass:     001614e4
    Size:        16(0x10) bytes
    File:        C:\dev2010\LOHRoots\LOHRoots\bin\Release\LOHRoots.exe
    Fields:
              MT    Field   Offset                 Type VT     Attr    Value Name
        64d42978  4000001        4             System.Int32      1     instance            1     &lt;X&gt;k__BackingField
        64d42978  4000002        8             System.Int32      1     instance            2     &lt;Y&gt;k__BackingField
</pre>
<p>Læg mærke til at begge arrays peger på samme element. Referencen i det store array er således rettet fra <code>026dfe1c</code> til <code>0242a570</code>, og dermed kan vi konkludere, at det store array er blevet opdateret på trods af, at applikationen ikke længere har nogen gældende reference til dette array.</p>
<p>Hvordan kan det være?</p>
<p>Tænker vi lidt over, hvad der sker under en garbage collection, giver det faktisk god mening, men det er måske ikke så intuitivt ved første øjekast.</p>
<p>En garbage collection lægger ud med at lave en analyse af hvilke objekter på den aktuelle del af heapen, der stadig er i brug. Disse markeres som værende i brug. Alle andre objekter kan ryddes op. Nøgleordet her er <em>den aktuelle del af heapen</em>. I og med at testprogrammet kører en <code>GC.Collect(1)</code> foretages denne analyse således kun for objekter der ligger i generation 0 og 1. Vores store array ligger på LOH, og er således ikke berørt af denne analyse.</p>
<p>Da oprydningen også iværksætter en flytning af objekterne i dette tilfælde, er garbage collection-rutinen nødt til at opdatere referencerne til de flyttede objekter, men da den på dette tidspunkt ikke ved, at vores store array ikke længere er i brug, er den nødt til at opdatere disse referencer.</p>
<p>Disponeringen giver god mening, hvis analysen af aktive rødder er mere omfattende end justering af referencerne. Skønt det optimale ville være at springe opdateringen over, kan det sagtens give mening at udføre denne – i teorien – overflødige handling, hvis disse forhold er til stede. Den analyse har jeg svært ved at lave, men jeg har været i kontakt med en af de ansvarlige udviklere, og Microsoft kender til problematikken, og derfor har jeg tillid til, at de har lavet de nødvendige analyser og undersøgelser. </p>
<p>Ændrer vi testapplikationen så den kalder <code>GC.Collect(2)</code> i stedet (eller blot <code>GC.Collect()</code>, der ligeledes laver en komplet oprydning), laver garbage collection-rutinen en fuld analyse af heapen og finder således ud af, at det store array ikke længere er i brug. I det tilfælde opdateres referencerne naturligvis ikke, da den nødvendige viden er tilgængelig i dette tilfælde. </p>
<p>Som nævnt tror jeg ikke, at dette er et reelt problem i nogen væsentlig udstrækning. For at denne situation skal have indflydelse på afviklingen, skal applikationen have mange midlertidige objekter på LOH, disse skal i stor udstrækning referere objekter på den almindelige heap, og compaction skal foretages jævnligt. I det tilfælde vil man muligvis kunne spore en effekt, men det er i realiteten et afledt problem af at have mange midlertidige objekter på LOH. Det er af flere grunde en dårlig ide, og dette er således kun en af flere uheldige konsekvenser af den situation. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=501</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Microsoft MVP Award 2010</title>
		<link>http://kodehoved.dk/?p=493</link>
		<comments>http://kodehoved.dk/?p=493#comments</comments>
		<pubDate>Thu, 01 Jul 2010 17:28:40 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[MVP]]></category>
		<category><![CDATA[Microsoft]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=493</guid>
		<description><![CDATA[For 3. gang i træk kan jeg sole mig lidt i indforstået, nørdet verdensberømmelse, idet jeg netop har fået besked om, at jeg har modtaget Microsofts MVP Award for 2010. Men selvom jeg har prøvet det før, er jeg alstå ikke mindre stolt af den grund. 
]]></description>
			<content:encoded><![CDATA[<p><img alt="Microsoft MVP" src="http://kodehoved.dk/images/MVP_FullColor_ForScreen.png"  class="alignright" width="60" height="94" />For 3. gang i træk kan jeg sole mig lidt i indforstået, nørdet verdensberømmelse, idet jeg netop har fået besked om, at jeg har modtaget Microsofts MVP Award for 2010. Men selvom jeg har prøvet det før, er jeg alstå ikke mindre stolt af den grund. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=493</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nyheder i C# 4 – fjerde del: ExpandoObject og DynamicObject</title>
		<link>http://kodehoved.dk/?p=485</link>
		<comments>http://kodehoved.dk/?p=485#comments</comments>
		<pubDate>Mon, 28 Jun 2010 10:12:54 +0000</pubDate>
		<dc:creator>Brian Rasmussen</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[.NET 4.0]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[C# 4.0]]></category>
		<category><![CDATA[dynamic]]></category>

		<guid isPermaLink="false">http://kodehoved.dk/?p=485</guid>
		<description><![CDATA[Efter en længere pause som følge af en svær lungebetændelse, fortsætter jeg her med fjerde indlæg i min serie om nyhederne i C# 4. 
I de foregående indlæg har vi set på motivationen for dynamiske typer, eksempler på brug af dynamiske typer og den underliggende infrastruktur for dynamiske typer. I dette indlæg er vi kommet [...]]]></description>
			<content:encoded><![CDATA[<p>Efter en længere pause som følge af en svær lungebetændelse, fortsætter jeg her med fjerde indlæg i min serie om nyhederne i C# 4. </p>
<p>I de foregående indlæg har vi set på <a href="/?p=453">motivationen for dynamiske typer</a>, <a href="/?p=471">eksempler på brug af dynamiske typer</a> og <a href="/?p=475">den underliggende infrastruktur for dynamiske typer</a>. I dette indlæg er vi kommet til to nye, dynamiske typer i .NET 4, <code>ExpandoObject</code> og <code>DynamicObject</code>.</p>
<h2>ExpandoObject</h2>
<p><code>ExpandoObject</code> er en type, der tillader, at vi kan modificere egenskaberne for konkrete instanser. Opretter vi en dynamisk instans af <code>ExpandoObject</code>, kan vi således tilføje properties, metoder og så videre til denne. Her er et eksempel, hvor vi tilføjer en property ved navn <code>Text</code>:</p>
<pre class="syntax-highlight:c#">
dynamic expando = new ExpandoObject();
expando.Text = &quot;hello world&quot;;
</pre>
<p>Herefter kan vi tilgå denne property på instansen på almindelig vis, og ganske som forventet udskriver nedenstående teksten <code>hello world</code>.</p>
<pre class="syntax-highlight:c#">
Console.WriteLine(expando.Text);
</pre>
<p>Denne egenskab gør, at vi kan skrive kode, der i nogle tilfælde bliver betydelig mindre omfattende, end vi er vant til. Lad os se på et eksempel. </p>
<p>Når vi arbejder med XML, er konstruktioner som nedenstående hyppige:</p>
<pre class="syntax-highlight:c#">
var movie = new XElement(&quot;Movie&quot;,
   new XElement(&quot;Title&quot;, &quot;Blade Runner&quot;),
   new XElement(&quot;Release&quot;, &quot;1982&quot;),
   new XElement(&quot;Cast&quot;,
      new XElement(&quot;Actor&quot;, &quot;Harrison Ford&quot;),
      new XElement(&quot;SupportingActor&quot;, &quot;Rugter Hauer&quot;),
      new XElement(&quot;Actress&quot;, &quot;Sean Young&quot;),
      new XElement(&quot;SupportingActress&quot;, &quot;Daryl Hannah&quot;)
   )
);

Console.WriteLine((string)movie.Element(&quot;Cast&quot;).Element(&quot;Actor&quot;));
</pre>
<p>Ved hjælp af <code>Element()</code>, kan vi udvælge specifikke dele af vores <code>XElement</code>-struktur. Dette er blot en af flere varianter over samme tema, men de fleste af dem fungerer ved, at vi bruger tekst til at navigere rundt i strukturen. I de tilfælde er brugen af dynamiske typer oplagt. </p>
<p>Ved hjælp af <code>ExpandoObject</code>, kan vi erklære en tilsvarende struktur således:</p>
<pre class="syntax-highlight:c#">
dynamic movie = new ExpandoObject();
movie.Title = &quot;Blade Runner&quot;;
movie.Release = &quot;1982&quot;;
movie.Cast = new ExpandoObject();
movie.Cast.Actor = &quot;Harrison Ford&quot;;
movie.Cast.SupportingActor = &quot;Rutger Hauer&quot;;
movie.Cast.Actres = &quot;Sean Young&quot;;
movie.Cast.SupportingActres = &quot;Daryl Hannah&quot;;
</pre>
<p>Fordi vores instans af <code>ExpandoObject</code> tilpasser sig det konkrete behov, kan vi blot tilføje egenskaber til objektet efter behov. Brugen ligner til forveksling den kode, vi ville skrive, hvis vi havde en eksplicit type til håndtering af vores film, men vi har ikke skrevet kode til erklæring af denne type. </p>
<p>Tilgang til dele af objektet ligner ligeledes den kode, vi ville skrive, hvis vi havde en eksplicit type:</p>
<pre class="syntax-highlight:c#">
Console.WriteLine(movie.Cast.Actor);
</pre>
<p>Bemærk at som jeg også var inde på i forrige indlæg, er det vigtigt, at instansen erklæres med typen <code>dynamic</code>, da det er denne angivelse, der tillader <code>ExpandoObject</code> at redefinere sig selv efter behov. Havde vi erklæret movie af typen <code>ExpandoObject</code>, havde vi fået en instans med denne statiske type, og dermed afskåret os selv mulighederne for at definere opførslen ved hjælp af det dynamiske metaobjekt. </p>
<p>Lad os udbygge eksemplet lidt. Hvordan ville det se ud, hvis vi havde brug for en samling af film-objekter baseret på <code>ExpandoObject</code>? Her er et bud:</p>
<pre class="syntax-highlight:c#">
var movies = new List&lt;dynamic&gt;();

movies.Add(new ExpandoObject());
movies[0].Title = &quot;Blade Runner&quot;;
movies[0].Release = 1982;

movies.Add(new ExpandoObject());
movies[1].Title = &quot;Alien&quot;;
movies[1].Release = 1979;

dynamic movie = new ExpandoObject();
movie.Title =  &quot;Delicatessen&quot;;
movie.Release = 1991;
movies.Add(movie);
</pre>
<p>Ikke mange overraskelser her og ganske som forventet, kan vi bruge LINQ på vores samling af film:</p>
<pre class="syntax-highlight:c#">
var movies80 = from m in movies
               where m.Release &gt;= 1980 &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; m.Release &lt; 1990
               select m.Title;

foreach(var m in movies80) {
    Console.WriteLine(m);
}
</pre>
<p>Som det fremgår, tilbyder <code>ExpandoObject</code> en simplere syntaks for eksemplerne i dette tilfælde. Performance er i begge tilfælde begrænset af de dynamiske opslag, så her adskiller brugen af <code>ExpandoObject</code> sig hverken i positiv eller negativ retning. Det er selvfølgelig værd at understrege, at syntaks ikke er alt, og hvis vi har en rig datamodel i koden, er vi bedre tjent med statiske typer, men <code>ExpandoObject</code> tilbyder et interessant alternativ i specifikke situationer. </p>
<h2>DynamicObject</h2>
<p><code>DynamicObject</code> tilbyder langt hen ad vejen den funktionalitet, vi så implementeret via <code>IDynamicMetaObjectProvider</code> i forrige indlæg. Det interessante ved <code>DynamicObject</code> er, at den fritager os for en del af arbejdet med implementering af dette interface ved at udstille et sæt virtuelle metoder, vi kan overstyre efter behov for at få lignende funktionalitet. </p>
<p>Har vi behov for en type, hvor vi kan omdefinere hele eller en del af den gængse opførsel, kan vi således med fordel gøre dette ved at lave en specialisering af <code>DynamicObject</code>. </p>
<p>Den åbenlyse begrænsning ved <code>DynamicObject</code> er, at at vi kun kan bruge den, hvis vi ikke har brug for yderligere specialiseringer. Skal vores type ligeledes arve fra en anden type, er vi nødt til at gå den slagne vej og implementere <code>IDynamicMetaObjectProvider</code> selv. I de resterende tilfælde kan vi med fordel gøre brug af <code>DynamicObject</code>s implementering. </p>
<p>Lad os se på et eksempel. </p>
<pre class="syntax-highlight:c#">
public sealed class DynamicType : DynamicObject {
   public override bool TryInvokeMember(
      InvokeMemberBinder binder,
      object[] args, out object result) {

      result = null;

      Console.WriteLine(&quot;Calling the method {0}&quot;, binder.Name);
      return true;
   }
}
</pre>
<p>Ovenstående type overstyrer <code>TryInvokeMember()</code>, hvilket vil sige, at hver gang, vi kalder en metode på en instans af denne type, vil vi få kaldt ovenstående. Vi kan derfor erklære en dynamisk instans og kalde et antal ikke-eksisterende metoder således:</p>
<pre class="syntax-highlight:c#">
dynamic d = new DynamicType();

d.Boing();
d.Boom();
d.Tschak();
</pre>
<p>Resultatet er udskriften <code>Calling the method Boing</code>, <code>Calling the method Boom</code> og <code>Calling the method Tschak</code>. Det er selvfølgelig ikke særlig brugbart i sig selv, men det illustrerer, hvordan vi kan redefinere, hvad det vil sige, at kalde metoder på en instans af denne type. </p>
<p>For et øjeblik siden påstod jeg, at <code>TryInvokeMember()</code> bliver kaldt hver gang, vi kalder en metode på en instans af vores type. Det er ikke helt korrekt. Havde det været korrekt, ville vi kunne implementere eksemplet fra forrige indlæg via <code>DynamicObject</code>, men det kan vi ikke. Kalder vi en metode, der findes på typen, bliver denne kaldt. Så hvis vi eksempelvis gør følgende:</p>
<pre class="syntax-highlight:c#">
Console.WriteLine(d.GetType());
</pre>
<p>Får vi udskriften <code>NewsInCS4.DynamicType</code> og ikke <code>Calling the method GetType</code>, som man ellers kunne tro. </p>
<p>Det skyldes, at <code>DynamicObject</code> først undersøger, om en given metode er tilgængelig via objektets statiske type. Så hvis vi kalder en eksisterende metode, kommer <code>TryInvokeMember()</code> ikke ind i billedet, og derfor kan vi ikke bruge <code>DynamicObject</code> til at implementere en type, hvor der er byttet om på to metoder. </p>
<p><code>DynamicObject</code> tilbyder således stort set de samme muligheder, som hvis vi selv implementerer <code>IDynamicMetaObjectProvider</code>, men da den fritager os for en del af implementeringsarbejdet, vil det i mange tilfælde være lettere at lave en specialisering af <code>DynamicObject</code> end at skulle implementere <code>IDynamicMetaObjectProvider</code>. </p>
]]></content:encoded>
			<wfw:commentRss>http://kodehoved.dk/?feed=rss2&amp;p=485</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
