sql >> Database >  >> RDS >> Database

Is de tekenreeksoperator "+" zo eenvoudig?

Inleiding

Een string-gegevenstype is een van de fundamentele gegevenstypen, samen met numerieke (int, long, double) en logische (booleaanse) gegevens. Je kunt je nauwelijks een nuttig programma voorstellen dat dit type niet gebruikt.

Op het .NET-platform wordt het stringtype gepresenteerd als een onveranderlijke String-klasse. Bovendien is het sterk geïntegreerd in de CLR-omgeving en wordt het ook ondersteund door de C#-compiler.

Dit artikel is gewijd aan concatenatie - een bewerking die op strings net zo vaak wordt uitgevoerd als de optelbewerking op cijfers. Je denkt misschien:"Wat valt er te zeggen?", we kennen tenslotte allemaal de tekenreeksoperator "+", maar het bleek dat het zijn eigen eigenaardigheden heeft.

Taalspecificatie voor tekenreeksoperator "+"

De C#-taalspecificatie biedt drie overbelastingen voor de tekenreeksoperator "+":

string operator + (string x, string y)

string operator + (string x, object y)

string operator + (object x, string y)

Als een van de operanden van tekenreeksaaneenschakeling NULL is, wordt de lege tekenreeks ingevoegd. Anders wordt elk argument, dat geen string is, weergegeven als een string door de virtuele methode ToString aan te roepen. Als de methode ToString NULL retourneert, wordt een lege tekenreeks ingevoegd. Opgemerkt moet worden dat volgens de specificatie deze bewerking nooit NULL mag retourneren.

De beschrijving van de operator is duidelijk genoeg, maar als we kijken naar de implementatie van de klasse String, vinden we een duidelijke definitie van slechts twee operatoren “==” en “!=”. Een redelijke vraag rijst:wat gebeurt er achter de schermen van stringconcatenatie? Hoe gaat de compiler om met de tekenreeksoperator "+"?

Het antwoord op deze vraag bleek niet zo moeilijk te zijn. Laten we de statische String.Concat-methode eens nader bekijken. De methode String.Concat voegt een of meer instanties van de klasse String of views samen als tekenreekswaarden van een of meer instanties van Object. Er zijn de volgende overbelastingen van deze methode:

public static String Concat (String str0, String str1)

public static String Concat (String str0, String str1, String str2)

public static String Concat (String str0, String str1, String str2, String str3)

public static String Concat (params String[] values)

public static String Concat (IEnumerable <String> values)



public static String Concat (Object arg0)

public static String Concat (Object arg0, Object arg1)

public static String Concat (Object arg0, Object arg1, Object arg2)

public static String Concat (Object arg0, Object arg1, Object arg2, Object arg3, __arglist)



public static String Concat <T> (IEnumerable <T> values)

Details

Stel dat we de volgende uitdrukking s =a + b hebben, waarbij a en b strings zijn. De compiler zet het om in een aanroep van een statische Concat-methode, d.w.z.

s = string.Concat (a, b)

De aaneenschakeling van tekenreeksen is, net als elke andere optelbewerking in de C#-taal, links-associatief.

Alles is duidelijk met twee rijen, maar wat als er meer rijen zijn? De uitdrukking s =a + b + c, gegeven de links-associativiteit van de bewerking, zou kunnen worden vervangen door:

s = string.Concat(string.Concat (a, b), c)

Gezien de overbelasting waarvoor drie argumenten nodig zijn, wordt het echter omgezet in:

s = string.Concat (a, b, c)

De vergelijkbare situatie is met de aaneenschakeling van vier strings. Om 5 of meer strings samen te voegen, hebben we de string.Concat overloading (params string[]), dus het is noodzakelijk om rekening te houden met de overhead die gepaard gaat met geheugentoewijzing voor een array.

Er moet ook worden opgemerkt dat de operator voor het samenvoegen van tekenreeksen volledig associatief is :het maakt niet uit in welke volgorde we strings aaneenschakelen, dus de uitdrukking s =a + (b + c), ondanks de expliciet aangegeven prioriteit van de uitvoering van de aaneenschakeling, wordt als volgt verwerkt

s = (a + b) + c = string.Concat (a, b, c)

in plaats van het verwachte:

s = string.Concat (a, string.Concat (b, c))

Dus, het voorgaande samenvattend:de bewerking voor het samenvoegen van strings wordt altijd van links naar rechts weergegeven en roept de statische String.Concat-methode aan.

Optimaliseren van compiler voor letterlijke tekenreeksen

De C#-compiler heeft optimalisaties met betrekking tot letterlijke tekenreeksen. Bijvoorbeeld, de uitdrukking s ="a" + "b" + c, gegeven de links-associativiteit van de "+"-operator, is gelijk aan s =("a" + "b") + c wordt omgezet in

s = string.Concat ("ab", c)

De uitdrukking s =c + "a" + "b", ondanks de links-associativiteit van de bewerking van aaneenschakeling (s =(c + "a") + "b") wordt omgezet in

s = string.Concat (c, "ab")

Over het algemeen doet de positie van de letterlijke waarden er niet toe, de compiler voegt alles samen wat hij kan en probeert pas dan een geschikte overbelasting van de Concat-methode te selecteren. De uitdrukking s =a + “b” + “c” + d wordt omgezet in

s = string.Concat (a, "bc", d)

Optimalisaties die zijn gekoppeld aan lege en NULL-tekenreeksen moeten ook worden vermeld. De compiler weet dat het toevoegen van een lege steek geen invloed heeft op het resultaat van de aaneenschakeling, dus de uitdrukking s =a + “” + b wordt omgezet in

s = string.Concat (a, b),

in plaats van de verwachte

s = string.Concat (a, "", b)

Evenzo, met de const string, waarvan de waarde NULL is, hebben we:

const string nullStr = null;

s = a + nullStr + b;

wordt geconverteerd naar

s = string.Concat (a, b)

De uitdrukking s =a + nullStr wordt geconverteerd naar s =a ?? “”, als a een string is, en de aanroep van de string.Concat methode(a), als a geen string is, bijvoorbeeld s =17 + nullStr, wordt het geconverteerd naar s =string.Concat (17) .

Een interessante functie die verband houdt met de optimalisatie van letterlijke verwerking en de links-associativiteit van tekenreeksoperator "+".

Laten we eens kijken naar de uitdrukking:

var s1 = 17 + 17 + "abc";

rekening houdend met de links-associativiteit, is het equivalent aan

var s1 = (17 + 17) + "abc"; // сalling the string.Concat method (34, "abc")

Als resultaat worden tijdens het compileren de cijfers toegevoegd, zodat het resultaat 34abc is.

Aan de andere kant, de uitdrukking

var s2 = "abc" + 17 + 17;

is gelijk aan

var s2 = ( "abc" + 17) + 17; // calling the string.Concat method ("abc", 17, 17)

het resultaat is abc1717.

Dus, daar ga je, dezelfde aaneenschakelingsoperator leidt tot verschillende resultaten.

String.Concat VS StringBuilder.Append

Het is noodzakelijk om een ​​paar woorden te zeggen over deze vergelijking. Laten we de volgende code eens bekijken:

string name = "Timur";

string surname = "Guev";

string patronymic = "Ahsarbecovich";

string fio = surname + name + patronymic;

Het kan worden vervangen door de code met StringBuilder:

var sb = new StringBuilder ();

sb.Append (surname);

sb.Append (name);

sb.Append (patronymic);

string fio = sb.ToString ();

In dit geval zullen we echter nauwelijks voordeel halen uit het gebruik van StringBuilder. Afgezien van het feit dat de code minder leesbaar is geworden, is deze min of meer effectief geworden, aangezien de implementatie van de Concat-methode de lengte van de resulterende string berekent en slechts één keer geheugen toewijst, in tegenstelling tot StringBuilder die niets weet over de lengte van de resulterende string.

Implementatie van de Concat-methode voor 3 strings:

public static string Concat (string str0, string str1, string str2)

{

if (str0 == null && str1 == null && str2 == null)

return string.Empty;

if (str0 == null)

str0 = string.Empty;

if (str1 == null)

str1 = string.Empty;

if (str2 == null)

str2 = string.Empty;

string dest = string.FastAllocateString (str0.Length + str1.Length + str2.Length); // Allocate memory for strings

string.FillStringChecked (dest, 0, str0); /

string.FillStringChecked (dest, str0.Length, str1);

string.FillStringChecked (dest, str0.Length + str1.Length, str2);

return dest;

}

Operator “+” in Java

Een paar woorden over de tekenreeksoperator "+" in Java. Hoewel ik niet in Java programmeer, ben ik toch geïnteresseerd in hoe het daar werkt. De Java-compiler optimaliseert de "+"-operator zodat deze de StringBuilder-klasse gebruikt en de append-methode aanroept.

De vorige code is geconverteerd naar

String fio = new StringBuilder(String.valueOf(surname)).append(name).append (patronymic).ToString()

Het is vermeldenswaard dat ze opzettelijk een dergelijke optimalisatie in C# hebben geweigerd, Eric Lippert heeft een bericht over dit onderwerp. Het punt is dat een dergelijke optimalisatie niet de optimalisatie als zodanig is, het is het herschrijven van code. Bovendien zijn de makers van de C#-taal van mening dat ontwikkelaars bekend moeten zijn met de aspecten van het werken met de String-klasse en, indien nodig, moeten overschakelen naar StringBuilder.

Trouwens, Eric Lippert was degene die werkte aan de optimalisatie van de C#-compiler die is gekoppeld aan de aaneenschakeling van strings.

Conclusie

Misschien lijkt het op het eerste gezicht misschien vreemd dat de klasse String de operator "+" pas definieert als we nadenken over de optimalisatiecapaciteit van de compiler met betrekking tot de zichtbaarheid van een groter codefragment. Als de operator "+" bijvoorbeeld is gedefinieerd in de klasse String, zou de uitdrukking s =a + b + c + d leiden tot het maken van twee tussenliggende tekenreeksen, een enkele aanroep van de tekenreeks.Concat (a, b, c, d) methode maakt het mogelijk om de aaneenschakeling effectiever uit te voeren.


  1. Gebruikt u de juiste tools voor het bewaken van databaseprestaties?

  2. mysql_insert_id alternatief voor postgresql

  3. Activex ListView Control-zelfstudie-01

  4. Functie voor datumnotatie in SQL Server