Lazy evaluated string interpolation

with No Comments

Sedan version 6 av C# har man haft stöd för string interpolation, och sedan dess har det varit möjligt att exekvera kod i en C#-sträng. Säkerhet uppnås genom att strängen utvärderas i det omfång (scope) som den skapas.

Det normala beteendet är att en sträng utvärderas i samma ögonblick som den skapas, vilket betyder att om man skickar en interpolerad sträng till en funktion, så är den utvärderad och klar när funktionen använder strängen. Strängen får inte innehålla fulla programsatser, endast uttryck. Följande kod visar hur strängen "11" skickas till en funktion som heter DoSomething:

För att infoga programsatser i en interpolerad sträng, måste uttrycket i strängen omvandlas till en delegat. I detta fall kommer funktionen DoSomething ta emot värdet "System.Delegate", eftersom det är strängrepresentationen av det som skickas in. Console.WriteLine exekveras inte, då koden egentligen beskriver en typomvandling.

Avslutande parenteser indikerar att delegaten ska anropas, men uttrycket i en sträng kan inte utvärderas till void, så typen måste utvärderas till en sträng. För att få kompilatorn att acceptera radbryte måste strängen vara ordagrann (verbatim string, @). Koden skickar värdet "Ok!" till funktionen, och uttrycket utvärderas alltså fortfarande direkt.

Om strängen ska utvärderas inuti funktionen DoSomething, måste funktionen godkänna detta. .NET stöder lazy evaluation genom den generiska klassen System.Lazy. Lazy evaluation kan förbättra prestandan genom att värden som kostar mycket prestanda att få fram, t.ex. en avancerad beräkning eller en komplicerad databasfråga, endast utvärderas om värdet verkligen blir använt. I detta exempel är strängen inkapslad i ett objekt, och funktionen tar en Lazy-instans som refererar till objektet. Först när funktionen DoSomething efterfrågar strängens värde utvärderas strängen, vilket illustreras av att "Injection" skrivs ut efter "Eval:", alltså i kroppen för DoSomething.

Apropå behörighet så är omfånget (scope) för koden inte klassen där exekveringen faktiskt sker (ImportantClass) utan klassen där strängen deklarerades (LazyClass). Detta ökar alltså inte risken för att injicerad kod använder resurser som den inte har tillgång till. C# tillåter endast att man anropar andra klassers privata medlemmar om medlemmarna är static. Detta exempel illustrerar hur en klass anropar privata funktioner i ett refererat klassbibliotek. Notera att koden förutsätter att funktionerna ger en retur och inte tar några parametrar, och att även property getters antas vara funktioner.

Om man inte känner till hur funktionerna fungerar kan man bl.a. anropa GetParameters eller ReturnTypeMethodInfo-objektet.

Följande kod är ett bra exempel på lazy evaluated string interpolation. En icke utvärderad sträng skickas till funktionen DoSomething, och när värdet väl läses av, samlar strängen in det data den behöver ha. Det skulle kunna vara ett tidsödande databasanrop, men i exemplet ställer strängen en fråga till användaren i konsolfönstret:

När värdet av MyString skrivs ut måste värdet först utvärderas, eftersom det inte är gjort i förväg, och för att utvärdera strängen måste en fråga ställas till användaren. Lazy evaluation bör alltså användas när man inte vet i förväg vilka strängar som kommer att läsas av.

Follow Anders Hesselbom:

Latest posts from

Leave a Reply