Extension metoder og C#

by Israr Khan 29. november 2010 13:05

Hadde litt diskusjoner rundt bruk av extension metoder på jobben i dag - og særlig med tanke på hvor det er fornuftig å bruke dette, og også hvordan.

Vi kom frem til en grei "konklusjon" om du kan kalle det med følgende retningslinjer:

  • Extension metoder skal tilby generisk funksjonalitet som er relevant i mer enn en kontekst.
  • Extension metoder skal tilby utvidet funksjonalitet til interface, og ikke til konkret type. Er det nødvendig å spesifisere en konkret type på extension-metoden, bør det vurderes om funksjonaliteten som tilbys heller bør være i implementasjonen av selve typen og ikke som en extension. 
  • Unntaket fra regel om å alltid lage extension for ett gitt interface og ikke en konkret type - er når du har en type du ønsker å utvide funksjonaliteten til, men ikke har tilgang til å faktisk gjøre dette. I slike tilfeller er det godtatt å utvikle extensionmetoder for en konkret type som utvider funksjonaliteten til denne typen. Eksempler på dette kan f.eks. være for å utvide tredjeparts API eller typen "objekt". Det bør uansett vises forsiktighet ved bruk av extension-metoder da vedlikehold av slik "ekstern" funksjonalitet kan fort vise seg å medføre mer overhead enn f.eks. å følge patterns av typen adapter, fasade e.l.

Twitter-quote of the day:

Ole - André Johansen
@ I suggest putting all your code in Extension Methods for Object.

Sjekk også ut:
http://codebetter.com/blogs/gregyoung/archive/2007/12/05/a-use-for-extension-methods.aspx

Adapter pattern:
http://en.wikipedia.org/wiki/Adapter_pattern

Facade pattern:
http://en.wikipedia.org/wiki/Facade_pattern

 

Edit: Ole-André hadde et annet scenario hvor bruk av extension metoder kan virke fornuftig:

En annen gyldig bruk av extension methods, sånn jeg ser det, er for å gruppere funksjonalitet. Hvis man for eksempel har et objekt som er mye brukt i en kodebase, kan det være befriende å gruppere funksjonaliteten som extension methods i forskjellige namespaces.


For eksempel om man har et Person-objekt, og man vil ha pensjon og forsikringsmetoder i forskjellige "pakker" som man kan inkludere og bruke på Person. person.BeregnPensjon(), og person.BeregnForsikringsPremie() kan leve i to forskjellige namespaces. Da kan de som jobber med pensjon slippe å se forsikringslogikken.


Extension Methods; handle with care Smile

Tags: , , , , ,

Koding

Bruk av extension-metoder i C#

by Israr Khan 27. november 2010 00:58
   1:  public static class CacheManager
   2:  {
   3:      public static Dictionary<string, Model.Product> _productCache;
   4:   
   5:      public static Dictionary<string, Model.Product> ProductCache
   6:      {
   7:          get
   8:          {
   9:              if (_productCache == null)
  10:                  _productCache = new Dictionary<string, Model.Product>();
  11:   
  12:              return _productCache;
  13:          }
  14:          private set
  15:          {
  16:          }
  17:      }
  18:   
  19:      public static bool CacheContains(this IDictionary cacheDictonary, string prefix, string key)
  20:      {
  21:          return cacheDictonary.Contains(string.Format(prefix, key));
  22:      }
  23:   
  24:      public static value GetFromCache<value>(this Dictionary<string, value> cacheDictonary, string prefix, string key)
  25:      {
  26:          return cacheDictonary[string.Format(prefix, key)];
  27:      }
  28:   
  29:      public static void AddToCache<value>(this Dictionary<string, value> cacheDictonary, string prefix, string key, value valueToAdd)
  30:      {
  31:          lock (cacheDictonary)
  32:              cacheDictonary.Add(string.Format(prefix, key), valueToAdd);
  33:      }
  34:   
  35:  }

Satt og skulle lage en enkel cache-manager som i sin enkleste form skulle består av en string-key for å identifisere elementet og T som verdi.

I utgangspunktet en enkel sak, en static Dictonary av typen String,T gjør susen, men deretter fant jeg fort ut at jeg i noen tilfeller ville få samme key, men value-elementet skulle være ulikt i cache-en. Da det er et begrenset antall forskjellige typer med samme key som vil bli brukt kunne jeg enten lage en cache-dictonary for hver type, eller så kunne jeg prefixe key med f.eks "sokeord/rabatt/vanlig", slik at sokeord_foo og rabatt_foo kan brukes for å differansiere to forskjellige instanser av foo som er cachet.

Ved bruk av cachen fant jeg fort ut av at det ble ganske så stygt med string.format(Konstanter.Cache.RABATT, "foo") overalt, og endte med å lage noen fine extension metoder som vist ovenfor :)

Posted using CodePoster"

Tags:

Koding

IIS warm up kun ved IIS-reset av server?

by Israr Khan 26. november 2010 11:59

IIS Warm Up kan være en fiffig sak som kan bli brukt til å dra opp en IIS-applikasjon til en gitt tilstand ved oppstart/recycle av applikasjonspoolen. Konkret tilfelle som jeg bruker det til nå er for å unngå Just-in-time-compile på en del regeltjenester som tar et halvt minutt eller mer på å compile.

For vårt tilfelle som har automatisk recycle av applikasjonspool-ene i gitte intervall, er dette fornuftig da gitt vi ikke hadde hatt dette - ville første bruker som kommer til siten måtte ventet de x-antall sekundene det tar å JIT-compile de regeltjenester som skal brukes, og det er ofte snakk om flere slike tjenester som compiles og dette er da ikke en ønskelig situasjon.

Konkret info om IIS Warmup er å finne på http://www.iis.net/download/applicationwarmup.

Det som ikke er fullt så fiffig er at slik warm up fungerer nå - så må hele serveren resettes for at warm up skal kjøres, og da selv om warm up er konfigurert per applikasjon i IIS. (Alternativt kan du også konfigurerer warm up per site men dette er ikke god nok granulering for vårt bruk). Dette betyr at når f.eks. en applikasjon blir oppdatert, noe som medfører at disse regeltjenestene igjen må recompiles blir ikke warm up som er konfigurert på applikasjonen kjørt før vi tar en full IIS reset.

Hvis vi velger å kjøre full IIS Reset - vil ulempen med dette være at alle sites og applikasjons-pooler med tilhørende applikasjoner går ned, og alle vil måtte kjøre varm up, i stedenfor at kun den ene applikasjonspoolen som hadde trengt det gjør det...

Edit:
Da fant jeg svar på issuet her - noe som i etterkant burde virke som veldig logisk, men det gjør nå det meste når en først har forstått det ;)
- En reset på server-nivå medfører en hard reset av alle applikasjonspooler - inkludert "recycle", og også warm up.


- En reset på site-nivå medfører ikke recycle av applikasjonspool, og heller ikke at warm up blir kjørt.


- En recycle på selve applikasjonspoolen medfører at warmup blir kjørt.

Tags: , ,

Generelt

Windows Phone 7 Theme Resources

by Israr Khan 22. november 2010 22:55

Kompisen min Tore Lervik (http://www.mindre.net ) har nettopp lagt ut en template for Windows Phone 7 som er nyttig for å kunne se resultatet når du bruker forskjellige themes ved utvikling :)

Sjekk ut : http://mindre.net/Article/windows_phone_7_theme_resources 

 

Tags: , ,

Windows Phone 7

CodePoster goes CodePlex

by Israr Khan 22. november 2010 15:26

CodePoster ligger nå ute på CodePlex! :)

http://codeposter.codeplex.com/

Tags: ,

CodePoster

Deserialisering av meldinger fra BizTalk 2008

by Israr Khan 8. november 2010 13:16

    public static T Deserialize<T>(XmlDocument xml,
string rootName, string rootNamespace) where T : class, new()
{
T t;
DataContractSerializer dcs;
MemoryStream ms;

dcs = new DataContractSerializer(typeof(T),
rootName, rootNamespace, knownTypes);
using (ms = new MemoryStream())
{
xml.Save(ms);
ms.Seek(0, SeekOrigin.Begin);
t = (T)dcs.ReadObject(ms);
}

return t;
}

public static T Deserialize<T>(XmlDocument xml,
string rootName, string rootNamespace) where T : class, new()
{
using (var nodeReader = new XmlNodeReader(xml))
{
nodeReader.MoveToContent();
var xdokumentet = XDocument.Load(nodeReader);
DataContractSerializer ser = new DataContractSerializer(typeof(T),
rootName, rootNamespace, knownTypes);

var reader = xdokumentet.CreateReader();
var returobjekt = (T)ser.ReadObject(reader);
reader.Close();
return returobjekt;
}
}

Har opplevd litt rar oppførsel ved deserialisering av XmlDocument fra BizTalk i en av hjelpekomponentene våre her på prosjektet.

Begge operasjonene våre ovenfor fungerer smertefritt når de kalles direkte fra C#-kode, og også med nøyaktig samme XmlDocument som BizTalk sender inn.

Når det kalles fra BizTalk på den andre siden, feiler begge.

For deserialiseren som bruker memorystream, blir string.empty konvertert til "\n\n\n", noe som medfører at sjekk på f.eks. string.IsNullOrEmpty vil feile, og også at disse verdiene vil bli lagret i databaser o.s.v.

For den andre deserialiseren hvor XmlDocumentet blir konvertert til et XDocument slipper vi unna problematikken med string.empty, men da får vi et litt mer pussig resultat:
Først gang komponenten blir kalt fungerer deserialiseringen, andre gang komponenten blir kalt feiler operasjonen med følgende feilmelding:

"...at Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception& exp) Additional error information: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. Exception type: SerializationException Source: System.Runtime.Serialization Target Site: Void HandleMemberNotFound(System.Runtime.Serialization.XmlReaderDelegator, System.Runtime.Serialization.ExtensionDataObject, Int32) The following is a stack trace that identifies the location where the exception occured at System.Runtime.Serialization.XmlObjectSerializerReadContext.HandleMemberNotFound(XmlReaderDelegator xmlReader, ExtensionDataObject extensionData, Int32 memberIndex)"

Har foreløpig ikke klart å løse opp i dette på en god måte - men problemet forsvinner tilsynelatende hvis du oppretter et nytt XmlDocument basert på det eksisterende XmlDocument-et sin InnerXml.toString(). Sært problem - og foreløpig står det uløst. Gi gjerne en tilbakemelding hvis du vet hva som faktisk skjer her... (Obs: Husk at begge operasjonene fungerer uten problemer når de kalles direkte fra C#)

Posted using CodePoster"

Tags: , , ,

Koding

Dagens kodekommentar

by Øyvind Støle-Hentschel 5. november 2010 11:08

//Tysklands hevn siden de tapte krigen
                lblEndreAttributtTypeStatus.ForeColor = System.Drawing.Color.Red;

Hvem sa at kodekommentarer var overflødige? :)

Posted using CodePoster"

Tags:

CodePoster 1.0 Beta lansert

by Israr Khan 5. november 2010 00:08

CodePoster 1.0 er endelig ute på nettet. Last ned, prøv ut og gi tilbakemeldinger på evt. feil og kom gjerne med tilbakemeldinger på funksjonalitet.

Sjekk ut: http://www.kodeverk.net/page/CodePoster-.aspx

Tags: , ,

CodePoster

Om meg

Kodeverk.net er drevet av .Net-utvikler Israr Khan.

Han jobber som gruppeleder og  seniorkonsulent for Capgemini Norge.

Hans fokusområder er alt innenfor .Net-verden, og har foreløpig tilgode å finne noe som han ikke finner av interesse innenfor teknologien. Han er drevet av genuin interesse for teknologi og lever for faget.


 

View Israr Khan's profile on LinkedIn

Month List