Archive for the ‘C# 4.0’ Category

Nyheder i C# 4 – sjette del: Bedre integration med COM

Thursday, July 22nd, 2010

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 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:

  • No-ref
  • Index properties
  • No PIA

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:

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;
}

Læg mærke til at COM-grænsefladen kræver, at alle parametre overføres via ref, 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 1 til get_Item(), er vi nødt til at oprette en reference til en boxed int med værdien 1, så vi kan overføre denne som en reference.

Heldigvis er der hjælp at hente i C# 4. No-ref fjerner behovet for at skrive alle de omfattende ref-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.

private void OpenWord() {
   var word = new Word.Application();

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

   word.Visible = true;
}

Læg mærke til, at alle de kedelige ref-kald er væk. De overflødige parametre er ligeledes fjernet, og compileren tillader nu, at vi kan nu kalde get_Item(), 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.

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 Primary Interop Assemblies, 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.

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.

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.

I næste og sidste indlæg i denne serie skal vi se på varians.

Nyheder i C# 4 – femte del: Valgfri og navngivne parametre

Tuesday, July 6th, 2010

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 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:

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);

Femten parametre skal der til at åbne et dokument i Word via COM. Femten!

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 ref, 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).

Med de nye tiltag i C# 4 ser ovenstående kald ud som følger:

word.Documents.Open("demo.docx", ReadOnly: true);

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.

Lad os se på et par yderligere eksempler. Betragt nedenstående metode:

public static void ListFilm(string title, int releaseYear = 2010, float score = 0f) {
   Console.WriteLine("{0} ({1}): {2}", title, releaseYear, score);
}

Ovenstående erklærer en metode med tre parametre: title er obligatorisk, mens releaseYear og score er valgfri. Vi kan altså kalde metoden på forskellig vis, f.eks.:

ListFilm("Delicatessen", 1991, 7.9f);

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

// udkommer i 2010 og vi regner med, at det er en god film
ListFilm("Les aventures extraordinaires d'Adèle Blanc-Sec", score: 8.0f);

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.

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.

For valgfri parametre indsætter compileren simpelthen de konkrete standardværdier ved oversættelse af metodekaldet.

For navngivne parametre bruges navnene til at identificere de korrekte placeringer for parametrene, og derefter genereres metodekald på almindeligvis.

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.

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.

I næste indlæg ser vi mere på forbedringerne omkring integration med COM.

Nyheder i C# 4 – fjerde del: ExpandoObject og DynamicObject

Monday, June 28th, 2010

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 til to nye, dynamiske typer i .NET 4, ExpandoObject og DynamicObject.

ExpandoObject

ExpandoObject er en type, der tillader, at vi kan modificere egenskaberne for konkrete instanser. Opretter vi en dynamisk instans af ExpandoObject, 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 Text:

dynamic expando = new ExpandoObject();
expando.Text = "hello world";

Herefter kan vi tilgå denne property på instansen på almindelig vis, og ganske som forventet udskriver nedenstående teksten hello world.

Console.WriteLine(expando.Text);

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.

Når vi arbejder med XML, er konstruktioner som nedenstående hyppige:

var movie = new XElement("Movie",
   new XElement("Title", "Blade Runner"),
   new XElement("Release", "1982"),
   new XElement("Cast",
      new XElement("Actor", "Harrison Ford"),
      new XElement("SupportingActor", "Rugter Hauer"),
      new XElement("Actress", "Sean Young"),
      new XElement("SupportingActress", "Daryl Hannah")
   )
);

Console.WriteLine((string)movie.Element("Cast").Element("Actor"));

Ved hjælp af Element(), kan vi udvælge specifikke dele af vores XElement-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.

Ved hjælp af ExpandoObject, kan vi erklære en tilsvarende struktur således:

dynamic movie = new ExpandoObject();
movie.Title = "Blade Runner";
movie.Release = "1982";
movie.Cast = new ExpandoObject();
movie.Cast.Actor = "Harrison Ford";
movie.Cast.SupportingActor = "Rutger Hauer";
movie.Cast.Actres = "Sean Young";
movie.Cast.SupportingActres = "Daryl Hannah";

Fordi vores instans af ExpandoObject 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.

Tilgang til dele af objektet ligner ligeledes den kode, vi ville skrive, hvis vi havde en eksplicit type:

Console.WriteLine(movie.Cast.Actor);

Bemærk at som jeg også var inde på i forrige indlæg, er det vigtigt, at instansen erklæres med typen dynamic, da det er denne angivelse, der tillader ExpandoObject at redefinere sig selv efter behov. Havde vi erklæret movie af typen ExpandoObject, 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.

Lad os udbygge eksemplet lidt. Hvordan ville det se ud, hvis vi havde brug for en samling af film-objekter baseret på ExpandoObject? Her er et bud:

var movies = new List<dynamic>();

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

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

dynamic movie = new ExpandoObject();
movie.Title =  "Delicatessen";
movie.Release = 1991;
movies.Add(movie);

Ikke mange overraskelser her og ganske som forventet, kan vi bruge LINQ på vores samling af film:

var movies80 = from m in movies
               where m.Release >= 1980 &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; m.Release < 1990
               select m.Title;

foreach(var m in movies80) {
    Console.WriteLine(m);
}

Som det fremgår, tilbyder ExpandoObject 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 ExpandoObject 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 ExpandoObject tilbyder et interessant alternativ i specifikke situationer.

DynamicObject

DynamicObject tilbyder langt hen ad vejen den funktionalitet, vi så implementeret via IDynamicMetaObjectProvider i forrige indlæg. Det interessante ved DynamicObject 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.

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 DynamicObject.

Den åbenlyse begrænsning ved DynamicObject 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 IDynamicMetaObjectProvider selv. I de resterende tilfælde kan vi med fordel gøre brug af DynamicObjects implementering.

Lad os se på et eksempel.

public sealed class DynamicType : DynamicObject {
   public override bool TryInvokeMember(
      InvokeMemberBinder binder,
      object[] args, out object result) {

      result = null;

      Console.WriteLine("Calling the method {0}", binder.Name);
      return true;
   }
}

Ovenstående type overstyrer TryInvokeMember(), 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:

dynamic d = new DynamicType();

d.Boing();
d.Boom();
d.Tschak();

Resultatet er udskriften Calling the method Boing, Calling the method Boom og Calling the method Tschak. 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.

For et øjeblik siden påstod jeg, at TryInvokeMember() 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 DynamicObject, men det kan vi ikke. Kalder vi en metode, der findes på typen, bliver denne kaldt. Så hvis vi eksempelvis gør følgende:

Console.WriteLine(d.GetType());

Får vi udskriften NewsInCS4.DynamicType og ikke Calling the method GetType, som man ellers kunne tro.

Det skyldes, at DynamicObject først undersøger, om en given metode er tilgængelig via objektets statiske type. Så hvis vi kalder en eksisterende metode, kommer TryInvokeMember() ikke ind i billedet, og derfor kan vi ikke bruge DynamicObject til at implementere en type, hvor der er byttet om på to metoder.

DynamicObject tilbyder således stort set de samme muligheder, som hvis vi selv implementerer IDynamicMetaObjectProvider, men da den fritager os for en del af implementeringsarbejdet, vil det i mange tilfælde være lettere at lave en specialisering af DynamicObject end at skulle implementere IDynamicMetaObjectProvider.

Nyheder i C# 4 – tredje del: The Object is King

Thursday, June 17th, 2010

Dette er tredje indlæg i en serie om nyhederne i C#. Foregående indlæg er her og her.

I forrige indlæg antydede jeg, at dynamic tilbyder større fleksibilitet end Reflection, og det skal vi se på i dette indlæg.

Sammen med C#s nye dynamic nøgleord er der ligeledes kommet nogle udvidelser til klassebiblioteket og afviklingsmiljøet for at understøtte de dynamiske egenskaber. Formålet er at understøtte et koncept, Microsoft har kaldt ”The Object is King”. Ideen er at introducere en abstraktion for, hvad det vil sige, at gøre noget på et objekt. Centralt i denne sammenhæng er det nye interface IDynamicMetaObjectProvider.

Hvis en type implementerer dette interface, betyder det, at typen selv håndterer, hvad det vil sige, at udføre forskellige operationer på instanser af typen. Mere specifikt betyder det, at typen kan returnere en instans af DynamicMetaObject, og det er denne instans, der står for nævnte funktionalitet. Ved at overstyre metoder i DynamicMetaObject, kan vi således definere objektets eksakte grundopførsel.

Lad os se på et eksempel, men lad os først få et par aspekter omkring statiske typer på plads. Betragt nedenstående metode:

public void SomeMethod(SomeType instance) {
   instance.Method();
}

Hvad sker der her? Som udgangspunkt får vi kaldt Method på en instans af typen SomeType. Hvis SomeType er en referencetype, Method er virtual, og det aktuelle objekt, instance peger på, er af en specialisering af SomeType, kan vi få kaldt en variant af Method. I begge tilfælde kan vi dog på oversættelsestidspunktet generere den specifikke kode, fordi C#s typebinding dikterer, hvad der skal ske her. (1)

Lad os nu forestille os, at vi flytter den handling der afgør, at vi kalder Method fra SomeType fra oversættelsestidspunktet til afviklingstidspunktet. Hvis metoden var erklæret som void SomeMethod(dynamic instance) ville det være præcis det, der ville ske, men lad os gå et skridt videre.

Lad os ydermere forestille os, at selve afgørelsen omkring, hvad det vil sige, at kalde en metode er blevet uddelegeret. I så fald er det ikke længere C#s statiske typesystem, der afgør, at effekten af instance.Method() er at kalde koden på SomeType associeret med Method(). I stedet kan vi implementere præcis den opførsel, vi har brug for. Det er, hvad IDynamicMetaObjectProvider tillader os.

Lad os se på et eksempel. Betragt nedenstående klasse:

public sealed class WeirdType : IDynamicMetaObjectProvider {
   public void Foo() {
      Console.WriteLine("Foo");
   }

   public void Bar() {
      Console.WriteLine("Bar");
   }

   public DynamicMetaObject GetMetaObject(Expression parameter) {
      return new WeirdTypeMetaObject(parameter, this);
   }
}

WeirdType har to simple metoder, Foo og Bar, der henholdsvis udskriver teksterne ”Foo” og ”Bar”. Kalder vi dem som følger, får vi helt som forventet udskriften: Foo efterfulgt af Bar.

var wt = new WeirdType();
wt.Foo();
wt.Bar();

(Husk var blot betyder, at compileren sætter typen af wt til den type, den kan udlede af tildelingen – altså WeirdType. Der er ikke noget magi, og det er ikke farligt.)

Derudover implementerer WeirdType IDynamicMetaObjectProvider og har derfor metoden GetMetaObject, som returnerer en instans af WeirdTypeMetaObject. Det betyder, at hvis vi kalder metoder på en dynamisk erklæret instans, vil det være opførelsen i det returnerede metaobjekt, der definerer den tilhørende funktionalitet. Det er lidt af en mundfuld, så lad mig prøve at konkretisere.

Som et illustrativt eksempel kunne vi få metaobjektet til at bytte om på metoderne, så når vi kalder Foo(), afvikles koden for Bar() og omvendt. For at gøre dette, skal vi implementere den nødvendige logik i WeirdTypeMetaObject.

Ændrer vi således ovenstående eksempel fra var til dynamic, vil compileren vide, at den er nødt til at overlade håndteringen af wt til afviklingsmiljøet, og eftersom typen implementerer IDynamicMetaObjectProvider, ved afviklingsmiljøet, at den aktuelle opførsel for instansen er defineret af vores metaobjekt.

For at gøre en lang historie kort: Kører vi nedenstående, får vi udskriften Bar efterfulgt af Foo, fordi vi har redefineret, hvad det vil sige, at kalde metoder på objektet.

dynamic wt = new WeirdType();
wt.Foo();
wt.Bar();

Eksemplet er selvsagt ikke det mest brugbare, men det illustrerer to vigtige pointer:

For det første viser det, at der kan gælde helt andre regler for, hvad det vil sige, at udføre operationer på en instans, når referencen til denne er erklæret som dynamic.

For det andet illustrerer det, at vi kan implementere regler, der ændrer de grundlæggende spilleregler fundamentalt. Det er en stærk feature, der kan åbne nogle døre i specielle situationer, men det er selvfølgelig også noget, der bør bruges med omtanke.

Definitionen af WeirdTypeMetaObject ser ud som følger:

public class WeirdTypeMetaObject : DynamicMetaObject {
   public WeirdTypeMetaObject(Expression expression, WeirdType value)
      : base(expression, BindingRestrictions.Empty, value) {}

   public override DynamicMetaObject BindInvokeMember(
      InvokeMemberBinder binder, DynamicMetaObject[] args) {

      Action action;

      if (binder.Name == "Bar") {
         action = new Action(((WeirdType) Value).Foo);
      } else if (binder.Name == "Foo") {
         action = new Action(((WeirdType) Value).Bar);
      } else {
         return base.BindInvokeMember(binder, args);
      }

      return new DynamicMetaObject(
         Expression.Block(
            Expression.Call(Expression.Constant(Value), action.Method),
            Expression.Default(typeof(object))
         ),
         BindingRestrictions.GetInstanceRestriction(Expression, Value),
         Value
      );
   }
}

Jeg vil ikke komme ind på detaljerne i ovenstående i dette indlæg, men jeg skal nok vende tilbage til det senere, da der er mindst en overraskelse, der kan drille lidt.

Ved at implementere IDynamicMetaObjectProvider får vi komplet kontrol over en types basale semantik. Desværre er det en lidt omstændelig affære at implementere dette interface, og hvis vi ikke har brug for at kunne kontrollere alt, tilbyder .NET to typer, der laver meget af arbejdet for os. I næste indlæg skal vi således se nærmere på DynamicObject og ExpandoObject.


  1. Faktisk ”snyder” Microsoft lidt her, for hvis SomeType er en referencetype genererer compileren et kald via callvirt, uanset om der er tale om en virtuel metode eller ej. Fordi vi kalder en metode via et referenceargument, kan referencen være null og derfor udnytter compileren, at callvirt laver et implicit null-tjek- Af den grund ser vi callvirt her i stedet for call.

Nyheder i C# 4 – andel del

Friday, June 11th, 2010

Dette er andet indlæg i en lille serie om nyhederne i C# 4. I forrige indlæg så vi på udviklingen af C#, og specifikt på motivationen for at udvide sproget med adgang til dynamiske typer. I dette indlæg skal vi se på et konkret eksempel på brug af dynamiske typer.

Så lad os kaste os ud i det. Betragt nedenstående stump kode:

Adder adder = GetAdder();
int result = adder.Add(40, 2);
Console.WriteLine(result);

Det er, som vi kender det. Ingen dynamiske typer. Det er plain vanilla C#, men lad os alligevel bruge et øjeblik på at slå fast, hvad der sker her.

Forudsat at vi har en type kaldet Adder med en metode kaldet Add, der tager to ints og returnerer en int samt en lokal metode ved navn GetAdder, der returnerer en instans af Adder, oversætter dette og fungerer som forventet.

Vi kan udføre det samme på dynamisk vis ved hjælp af Reflection. I så fald ser kode ud som følger:

object adder = GetAdder();
Type adderType = adder.GetType();
object returnObject = adderType.InvokeMember("Add",
   BindingFlags.InvokeMethod, null, adder, new object[] { 40, 2 });
int result = Convert.ToInt32(returnObject);
Console.WriteLine(result);

Ikke alene fylder dette en del mere, det er også sværere at læse, men den grundlæggende funktionalitet er som ovenfor.

Vi har stadig en GetAdder(), men da vi ikke vil lægge os fast på en bestemt type til returværdien, er vi nødt til at betragte den som en instans af object.

Vi vil stadig gerne kalde Add(), men for at kunne gøre det via Reflection, er vi nødt til at have fat i den aktuelle type på returværdien fra GetAdder() først. Via typeobjektet kan vi kalde metoden, men vi er nødt til at beskrive signaturen, hvordan typebinding skal foretages, hvilken instans metoden skal kaldes for samt de relevante argumenter til metoden. Derfor bliver kaldet til InvokeMethod() ret omfattende.

Returværdien er ligeledes repræsenteret via en instans af object, så for at få pillet værdien ud af denne, er vi nødt til at kalde ToInt32(), og herefter er vi i mål.

Ulemperne ved ovenstående er indlysende. Det er tungt at skrive og tungt at læse. Der er adskillige muligheder for fejl på afviklingstidspunktet. Måske har typen ikke en Add(), måske er argumenterne ikke korrekte, måske får vi noget tilbage, der ikke kan konverteres til int.

Dertil kommer, at hver gang vi kalder ovenstående, skal alle disse elementer verificeres, og det tager naturligvis lidt tid.

Hvad er fordelen så? Fordelen er, at ovenstående virker, uanset hvad GetAdder() end returnerer, så længe der er tale om en instans, der har en Add() med den korrekte signatur. Koden er således ikke afhængig af specifikke typer, men derimod specifikke egenskaber ved vilkårlige typer.

Med dynamiske typer får vi større fleksibilitet samt bedre ydelse med en syntaks, der ligger meget tæt op ad den vi kender fra statiske typer. Med dynamiske typer ser koden således ud:

dynamic adder = GetAdder();
dynamic result = adder.Add(40, 2);
Console.WriteLine(result);

Nu ligner koden til forveksling, det vi kender med den ene forskel, at vi har udskiftet de statiske typer med det nye nøgleord dynamic. Ligesom Reflection-eksemplet fungerer dette, uanset hvad GetAdder() end returnerer, så længe den returnerede instans kan honorere kaldet til Add(). Det er fleksibelt og letlæseligt.

Vi har naturligvis stadig samme faldgruber som ved Reflection. Hvis metoden ikke findes, får vi en fejl på kørselstidspunktet. Hvis argumenterne til metoden ikke passer, får vi ligeledes en afviklingsfejl. I teorien kunne vi også få en fejl, hvis WriteLine ikke kunne kaldes med den konkrete instans af result, men eftersom WriteLine() ender med at kalde ToString(), som instansen får fra object, er der ingen ko på isen her.

Den tilgængelige syntaks er ikke den eneste fordel. I vores Reflection-eksempel betaler vi prisen for dynamikken ved hvert kald, så hvis vi kalder ovenstående i en løkke, kommer programmet til at lave det samme arbejde mange gange. Vi kan selvfølgelig gemme resultatet af forarbejdet og genbruge det i løkken, men det kræver mere kode.

Med DLRen får vi dette forærende af selve afviklingsmiljøet i form af call site caching, så når den specifikke Add() metode er blevet identificeret for vores aktuelle instans, gemmes denne oplysning og genbruges automatisk, hvis vi f.eks. kalder Add() flere gange i en løkke.

Okay, er humlen så, at vi blot har fået pænere og hurtigere Reflection? Ikke helt for dynamic kan mere end Reflection, men det ser vi på i næste indlæg.

Nyheder i C# 4 – første del

Friday, June 4th, 2010

Dette er første indlæg i en lille serie omkring nyhederne i C# 4.

Med frigivelsen af Visual Studio 2010, har vi også fået adgang til den nyeste version af C#, men der er meget mere end det på tapetet. Ikke alene har Visual Studio gennemgået en større om- og udbygning. .NET afviklingsmiljøet, klassebiblioteket og C# er alle ligeledes blevet opdateret med nye features.

Jeg vil i første omgang begrænse mig til nyhederne i selve C# sproget, men i senere indlæg vil jeg også komme ind på nogle af nyhederne i klassebiblioteket.

Nyhederne i C# 4 er:

Men først …

Lidt historie

C# har gennemgået en omfattende udvikling gennem årene. Den første version kom i 2002 og blev af mange betragtet som en Redmond-version af Java. Sprogene lignede da også hinanden til forveksling, men de begyndte allerede at divergere i 2005, da version 2 tilføjede generics til ikke bare sproget men også til selve afviklingsmiljøet. Dermed adskilte C# sig fra både Java og C++ på dette punkt.

C#s udvikling

I 2007 introducerede Anders Hejlsberg og Co. Language INtegrated Query, LINQ, og dermed fik C# et sæt ret unikke features, der var med til at lægge afstand til Java.

Seneste skud på stammen er muligheden for at arbejde med dynamiske typer. Så til alle dem, der råbte vagt i gevær omkring brugen af var: Det er nu, I skal være bange.

Sammenlignet med de to forrige versioner af C#, er denne nyhed muligvis ikke så revolutionerende. Har man brug for at arbejde med dynamiske typer, vil man værdsætte de nye tiltag, men hvis alle ens udfordringer kan løses med statiske typer, vil de nye muligheder muligvis kun bidrage som ammunition i den verserende skyttegravskrig mellem tilhængere af henholdsvis dynamiske og statiske sprog.

I modsætning til generics og LINQ vil dynamiske typer ikke ændre den gængse brug af sproget, men det er et værktøj, der er særdeles anvendelig i visse situationer.

Dynamiske typer

Hvad er dynamiske typer, og hvad er der sket med .NET for at imødekomme brugen af disse?

Svaret på det første spørgsmål er, at dynamiske typer er typer, hvor undersøgelser og beslutninger omkring typernes egenskaber foretages på afviklingstidspunktet i stedet for på oversættelsestidspunktet.

Så de tjek, compileren normalt laver som en del af oversættelsen, laves i stedet på afviklingstidspunktet. Det vil selvfølgelig også sige, at de fejl, der under normale omstændigheder ville give fejl under oversættelsen, giver nu fejl under kørslen i stedet.

Det er der ikke noget nyt i. Konceptet findes allerede i mange andre sprog som f.eks. Javascript, Perl, Python, Ruby og mange andre. Det nye består i, at C# nu tillader, at typer kan opføre sig på denne måde, og vi kan således have kode, der benytter såvel statiske som dynamiske typer.

Svaret på det andet spørgsmål er lidt mere omfattende. CLRen har nemlig fået et sæt af udvidelser, der tilsammen betegnes Dynamic Language Runtime eller blot DLR.

Dynamic Language Runtime

Overordnet set tilbyder DLRen i skrivende stund tre komponenter:

Dynamic dispatch er den mekanisme, der gør den dynamiske håndtering mulig. I C# er det repræsenteret ved dels et nyt reserveret ord, dynamic samt et interface, IDynamicMetaObjectProvider, der angiver, hvordan det dynamiske skal opføre sig. Hvis en type implementerer dette interface, er det et signal til afviklingsmiljøet om, at der gælder specielle regler for, hvad det vil sige at udføre operationer på instanser af denne.

Expression trees er som sådan ikke nye, men de er blevet udvidet til at kunne håndtere de nødvendige sprogkonstruktioner.

Call site caching er en optimering, der gør, at omkostningerne ved dynamiske opslag på afviklingstidspunktet reduceres. Første gang en metode kaldes på et dynamisk objekt, er afviklingsmiljøet nødt til at finde ud af, hvad det vil sige, at kalde denne metode. Denne operation tager tid, så derfor gemmer afviklingsmiljøet resultatet, så det kan genbruges for lignende operationer.

Med de faciliteter DLRen stiller til rådighed, er det let at implementere nye dynamiske sprog i .NET-verden. De to mest populære for tiden er nok IronPython og IronRuby.

Det essentielle er dog ikke, at vi har fået et par nye, hippe sprog. Den store nyhed er, at afviklingsmiljøet nu tilbyder en platform til implementering af disse eller dele deraf. Da de dynamiske faciliteter er en del af infrastrukturen, får vi en masse af den grundlæggende forærende, og det er ret interessant. På samme måde som CLRen giver os en fælles platform på tværs af sprog, giver DLRen os nu et fundament til at bygge dynamiske systemer.

Vi kan afvikle kode skrevet i dynamiske sprog som IronPython eller IronRuby, vi kan interagere med dynamiske miljøer som COM, DOM og så videre, og vi kan lade dele af vores system implementere en dynamisk adfærd, som vi definerer. Alt dette vil jeg se nærmere på i de efterfølgende indlæg.

ANUG Visual Studio 2010 Launch Event

Friday, May 21st, 2010

Jeg tog en fridag fra min ferie i går og tilbragte dagen i selskab med over 200 andre .NET-entusiaster til ANUGs Visual Studio 2010 Launch Event i Århus. Det var en rigtig god dag med masser af interessant indhold på programmet og god mulighed for networking.

Jeg holdt en lettere reduceret udgave af min Nyheder i C# 4 Tech Talk. Det gik stærkt, da jeg kun havde 45 minutter, men jeg har fået mange positive tilbagemeldinger, så det gik åbenbart ganske fint.

Dagens bedste indlæg var efter min mening Rasmus Kromann-Larsens introduktion til Resharper 5. Demoerne var velvalgte, lærerige og ikke mindst underholdende. Rasmus udviste godt overblik og præsentationen forløb rigtig godt.

Jeg synes også, at Rasmus Wulff Jensens indlæg om nyheder i Visual Studio 2010 fortjener at blive fremhævet. Han havde ligeledes godt styr på materialet, kom fint rundt i nyhederne og havde gode eksempler til at illustrere det hele med.

Dagens største skuffelse var desværre det indlæg, jeg havde set mest frem til. Carsten Juel Andersens indlæg om Task Parallel Library var desværre noget rodet, og der var for mange unøjagtigheder til min smag. Eksempler var fint præsenteret, men desværre ikke alle lige velvalgte. Pointen med en thread safe collection er jo ikke, at man kan gennemløbe den, samtidig med at man modificerer den. Og så er thread safe altså noget man ligesom graviditet enten er eller ikke er. Man kan altså ikke være hverken 30% gravid eller delvis thread safe.

Det ændrer dog ikke ved, at arrangementet som helhed var glimrende og udførelsen i top. Jeg havde tilmed fornøjelsen at spise aftensmad med et par af arrangørerne og de andre taler, hvilket var en god afslutning på en udbytterig dag.

Stor tak til ANUG og de mange fremmødte.

Der er yderligere indtryk fra dagen på ANUGs hjemmeside.