by DotNetNerd
22. March 2009 13:17
Et sted jeg ofte oplever friktion imellem practices og frameworks er imellem godt objektorienteret design og webudviklings frameworks. Veldesignede objekter er sjældent specielt velegnede til f.eks databinding og serialisering. Eksempelvis kaster serialiseringsprocessen i MVC frameworket en exception, hvis man forsøger at serialisere et objekt der er del af en mange til mange relation (hvor to klasser har collections indeholdende instancer af hinandens typer). Det giver fint mening at det forholder sig sådan i en serialiseringskontekst, men omvendt kan man ikke i sit design undvære mange-til-mange relationer. I forhold til databinding kan det være et issue at man gerne vil databinde et objekt hvor nogle properties er komplekse typer, hvorfra der skal noget logik til at afgøre hvilken værdi der skal representere objektet i brugerfladen.
Løsningen på den slags udfordringer er ofte at lave en ViewData klasse der som udgangspunkt er et subset af den oprindelige klasse. Properties som er mere komplekse kan så fjernes eller ændres, og udregnede eller relaterede data kan tilføjes viewet. Som bekendt er der ingen designbeslutninger uden konsekvenser, og her er den tydelige konsekvens at man nu skal skrive kode til at mappe imellem entiteter og viewdata. I mange tilfælde er det virkelig trivielt, da properties navngives ens, så for at undgå at skulle gøre dette manuelt skrev jeg en MapToView metode.
public static ViewType MapToView<EntityType, ViewType>(EntityType entity) where ViewType : new()
{
var view = new ViewType();
var entityType = entity.GetType();
var viewType = view.GetType();
foreach(var property in entityType.GetProperties())
{
var viewProp = viewType.GetProperty(property.Name);
if(viewProp != null && viewProp.PropertyType == property.PropertyType)
{
viewProp.SetValue(view, property.GetValue(entity, null), null);
}
}
return view;
}
Den er naturligvis reflection baseret, og så siger ens barnelærdom jo at man skal passe på hvad det betyder for performance. En helt kort test hvor jeg har to klasser med 10 string properties som jeg mapper 1000 gange viste over 5 observationer at det tager ca. 53 gange så lang tid med MapToView frem for med manuel mapning. Det skal dog ses i det lys at vi snakker omkring 145 millisekunder på en 3,2 GHz Pentium 4 for de 1000 mapninger - så med mindre der virkelig er skarpe designkrav omkring performance vil det næppe være et issue.