Archive for the ‘C# 3.0’ Category

var eller ej, det gør næppe den store forskel

Thursday, May 14th, 2009

C# 3 introducerede som bekendt et væld af nye features og muligheder. Der er allerede skrevet rigtig meget om LINQ, extension methods og så videre, men hvis der er en enkelt feature, der i den grad er blevet overeksponeret, er det nye var-keyword. Med jævne mellemrum synes en eller anden blogger, at det er tid til en opsang omkring brugen af var, og senest har Microsofts danske udviklerevangelist meldt sig i koret af folk, der vil advare mod de grelle konsekvenser ved brugen af dette udskældte keyword.

Jeg ser ikke noget formål i at forsøge at argumentere for, hvorfor jeg ser var som en genial, lille feature. I stedet vil jeg blot slå fast, at jeg bruger var til stort set alle lokale variable, og jeg glæder mig derfor over, at ReSharper understøtter mine præferencer på det punkt.

Den interessante debat er ikke, om var gør koden mere eller mindre læselig. Det interessante er, at brugen af var eller ej ikke har nogen nævneværdig indflydelse på læsbarheden af koden. Bevares, vi kan argumentere for, at der er en forskel, men uanset hvilket synspunkt vi tilslutter os, er der næppe nogen af os, der vil påstå, at brugen af var er den altafgørende forskel mellem læsbar og ulæselig kode.

Tager vi let læselig kode og skifter alle eksplicitte erklæringer ud med var, vil nogen hævde, at koden bliver en smule pænere, mens andre vil argumentere for, at den bliver lidt mindre læselig, men der er næppe nogen, der vil påstå, at den før læsbare kode nu er helt ulæselig. Analogt kan vi tage rodet, ulæselig kode og enten indføre eller eliminere brugen af var, uden at det vil udrette noget væsentlig. Ja, der er en forskel, men nej den er ikke så udslagsgivende, at var fortjener al denne opmærksomhed. 

Jeg har allerede skrevet lidt om, hvad jeg betragter som vigtige egenskaber ved læsbar kode, men for blot at repetere et par pointer er sigende navne til variable og metoder samt korte, velafgrænsede typer og metoder langt vigtigere for læsbarheden end brugen af enten implicitte eller eksplicitte typeerklæringer. var er og bliver altså ikke det store problem. 

Så til alle jer, der råber vagt i gevær, hvis I skal komme med gode råd til hvordan vi kan skrive bedre kode, er var altså ikke det rette sted at begynde.

Opgrader gamle collections til LINQ – andet forsøg

Monday, March 30th, 2009

I begejstring over at have fundet OfType<T>-metoden til IEnumerable, gjorde jeg mig desværre ikke den ulejlighed at undersøge sagen til bunds, så derfor opdagede jeg ikke, at der er to metoder til det formål. 

IEnumerable er nemlig blevet udvidet med både OfType<T> og Cast<T>. De implementerer sammen funktionalitet, nemlig at oversætte IEnumerable til IEnumberable<T>, men måden, de gør det på, er forskellig.

OfType<T> tager de elementer fra samlingen, der kan oversættes til T og gennemløber disse. Så hvis vi har en blandet collection som f.eks. 

var mixed = new ArrayList() { 42, "hello", 1337, "world" };
foreach (var element in mixed.OfType<int>()) {
   Console.WriteLine(element);
}

vil OfType<T> kun behandle de to heltal, 42 og 1337 og springe de to tekster over. 

Cast<T> tager derimod hver element og laver et cast til T, så hvis vi forsøger at bruge Cast<int> på ovenstående, får vi en InvalidCastException, da "hello" og "world" ikke kan castes til int

I mit Regex-eksempel ved vi, at de enkelte elementer er af typen Match, så her vil det være mest oplagt, at bruge Cast<T> frem for OfType<T>, som jeg først havde valgt. Eksemplet ser derfor ud som følger:

static void Main(string[] args) {
   var input = "3249785x329x48572938x79287459328576923" +
      "489263592374x598237459x236459812x73459872918798" +
      "7192871293874x1923857319487x510237x203012374127" +
      "34234912873501723x501293741x243452345x234523403";

   var pattern = @"\d";

   foreach (var match in Regex.Matches(input, pattern)) {
      Console.WriteLine(match);
   }

   var query = Regex.Matches(input, pattern).Cast<Match>()
      .GroupBy(match => match.Value)
      .OrderBy(grouping => grouping.Count());

   foreach (var entries in query) {
      Console.WriteLine("{0} = {1}", entries.Key, entries.Count());
   }
}

Opgrader gamle collections til LINQ

Wednesday, March 25th, 2009

(Bemærk: Dette indlæg har flere detaljer om nedenstående)

Klassebiblioteket til .NET kommer med et hav af brugbare klasser. En del af disse har været med siden den spæde begyndelse og nyder således ikke glæde af generics, der som bekendt først blev indført i .NET 2.0. 

Eksempelvis returnerer Regex.Matches ikke en IEnumerable<Match>, men derimod en MatchCollection, der er en specifik indkapsling af en ArrayList indeholdende instanser af Match. Der er andre eksempler på metoder, der returnerer sådanne specifikke Collections. MatchCollection og lignende implementer såvel ICollection som IEnumerable, så vi kan let løbe dem igennem, men da de ikke implementerer IEnumerable<T>, kan vi desværre ikke umiddelbart bruge LINQ.

Til alt held er IEnumerable blevet udvidet med en extension method, OfType<T>, der tager en IEnumerable og laver den om til en Enumerable<T>. Har man læst grundigere på LINQ, end jeg tilsyneladende har, er dette næppe en nyhed, men jeg har altså først fundet den nu. Jeg skal ikke kunne sige, hvordan jeg har overset denne fremragende feature, men nu hvor jeg er blevet opmærksom på den, vil jeg i hvert fald gøre mit til, at andre ikke overser den. 

Hvad kan vi så bruge OfType<T> til? Hvis vi fortsætter med Regex-eksemplet, har vi nu mulighed for at kombinere Regex’s stærke søgefunktionalitet med LINQs ditto forespørgselsfunktionalitet. Lad os se på et lille eksempel. 

static void Main(string[] args) {
   var input = "32497x85329485x72938792x87459328576923" +
      "4892635923745982374xx5923645981273x459872918798" +
      "719287129387x419238573194x87510237203x012374127" +
      "3423491x287350172x3501293741x243452345234523403";

   var pattern = @"\d";

   var query = Regex.Matches(input, pattern).OfType<Match>()
      .GroupBy(match => match.Value)
      .OrderByDescending(grouping => grouping.Count());

   foreach (var entries in query) {
      Console.WriteLine("{0} : {1}", entries.Key, entries.Count());
   }
}

 
Ovenstående leder efter cifre i input bestående af cifre og støj (x) ved hjælp af et simpel regular expression. Resultatet er en MatchCollection. Ved hjælp af OfType<T> konverterer vi denne til IEnumerable<T> og bruger derefter LINQ til at gruppere og tælle forekomsterne af de enkelte cifre for til sidst at udskrive det samlede resultat sorteret efter hyppighed som illustreret nedenfor.

2 : 27
3 : 26
7 : 21
9 : 20
4 : 19
8 : 16
5 : 16
1 : 13
0 : 6
6 : 3

Det, synes jeg, er cool. Det kan selvfølgelig laves på andre måder, men det her er kort og præcis (og i dette tilfælde er det faktisk kortere at kalde extension methods end at bruge LINQs forespørgselssprog).

Eksemplet er selvfølgelig meget simpelt, men forestil dig, at vi ikke leder efter cifre men derimod IP-adresser i en logfil til en webserver. Så er det blot at ændre vores Regex for at ovenstående giver en en komplet rapport over besøgende sorteret efter hyppighed. Kombinationen af Regex og LINQ er ret potent.

Videoer fra Jon Skeet

Tuesday, November 18th, 2008

Jeg er på Øredev lige nu. Min workshop gik fint, men jeg er træt som bare pokker, så der kommer først en update med detaljer lidt senere.

For dem, der missede Jon Skeet og til dem, der gerne vil genopleve dagen: Videoerne er nu tilgængelige. God fornøjelse.

Materiale fra en dag med Jon Skeet

Wednesday, November 5th, 2008

Jeg har lagt en zip-fil med slides og kodeeksempler fra Jons præsentation til download. God fornøjelse.

Videoen er ikke på trapperne endnu, men jeg skal nok sige til.

En dag med Jon Skeet

Friday, October 31st, 2008

I går havde jeg fornøjelsen af at være vært for Jon Skeet, der var kommet forbi en hel dag for at fortælle os om C# 2, 3, 4 og tilmed give et par ideer til hvad, der muligvis kan blive til C# 5, når vi engang, når så langt. Jeg synes, det var en glimrende dag, og jeg håber, at deltagerne gik derfra med en god oplevelse.

Jons præsentation bestod af et mindre antal slides, som jeg linker til, når de bliver tilgængelige samt en pokkers masse kode, der i høj grad blev til under sessionen. Det regner jeg også med bliver tilgængelig. Sidst men ikke mindst blev hele seancen optaget, så når det er blevet redigeret, kommer der også en video, hvor man ud over at høre alle Jons guldkorn kan se undertegnede som data source i dramatiseringen af LINQ. Flere detaljer og links senere. 

Jon har selvfølgelige allerede en post om arrangementet, og vi er begge meget interesserede i at høre respons fra deltagerne, så skriv gerne et par kommentarer her eller der.

Tak til Jon for en underholden og oplysende dag, tak til Microsoft for at lægge hus til og tak til alle jer, der dukkede op og var med til at gøre det til et glimrende arrangement. 

Ja tak til kompakt kode

Wednesday, October 29th, 2008

“One-liners er bare så 1995″, skrev Klaus Hebsgaard i en kommentar. For mit vedkommende stod 90erne i høj grad i C++s tegn, og det var der altså ikke meget one-liner over. Det løber mig stadig koldt ned af ryggen, når jeg tænker på templates i C++, men lad det nu ligge. Det er lang tid siden,  jeg har haft fingrene i den slags, og jeg savner det faktisk ikke. Nu går min tid hovedsagelig med C#, så lad os tale lidt om, hvordan one-liners har det i C#.

Hvis one-liners er et fænomen, der hører midt 90erne til, har den seneste inkarnation af C# vel taget et par skridt tilbage mod svundne tider. Mange af de nye tiltag i C# 3 går i hvert fald på at gøre sproget mindre teksttungt. Det bifalder jeg. 90er-stil eller ej.

Det gode er jo, at sproget stadig tillader, at vi stadig kan overspecificere koden i en grad, der gør den næsten ulæselig, så hvis vi vil følge Klaus’ eksempel, kan vi skrive:

IEnumerable<string> seventiesmovies = Enumerable.Select<Movie, string>(
   Enumerable.OrderBy<Movie, string>(
   Enumerable.Where<Movie>(movies, delegate(Movie movie) {
      if(movie.ReleaseYear >= 1970 && movie.ReleaseYear <= 1979) {
         return true;
      } else {
         return false;
      }}) ,
   delegate(Movie movie) { return movie.Title; }),
   delegate(Movie movie) { return movie.Title; }
);

Men hvis vi hellere vil hylde 1995 og de nye toner i C#, kan vi også bare skrive:

var seventiesmovies = from movie in movies
   where movie.ReleaseYear >= 1970 && movie.ReleaseYear <= 1979
   orderby movie.Title
   select movie.Title;

Jeg skal indrømme, at jeg ikke ved, om Klaus rent faktisk foretrækker det første eksempel, og det er ikke min mening at hænge Klaus ud, så jeg håber, at du, kære læser og Klaus i særdeleshed, vil fange at dette er skrevet med et glimt i øjet.

Jeg synes blot, at jeg ville slå endnu et slag for kompakt kode. Undskyld Klaus.