Ile obiektów typu String zostanie utworzonych przy użyciu znaku plus w poniższym kodzie?
String result = "1" + "2" + "3" + "4";
Gdyby było tak, jak poniżej, powiedziałbym trzy obiekty typu String: „1”, „2”, „12”.
String result = "1" + "2";
Wiem również, że obiekty String są buforowane w puli / tabeli String Intern w celu poprawy wydajności, ale nie o to chodzi.
Odpowiedzi:
O dziwo, to zależy.
Jeśli zrobisz to metodą:
wtedy kompilator wydaje się emitować kod używając
String.Concat
odpowiedzi @Joachim (+1 do niego btw).Jeśli zdefiniujesz je jako stałe , np .:
lub jako dosłowne , jak w pierwotnym pytaniu:
wtedy kompilator zoptymalizuje te
+
znaki. Jest to równoważne z:Ponadto kompilator usunie zbędne wyrażenia stałe i wyemituje je tylko wtedy, gdy są używane lub ujawniane. Na przykład ten program:
Generuje tylko jeden ciąg - stałą
result
(równą „1234”).one
itwo
nie pojawiają się w wynikowym IL.Pamiętaj, że w czasie wykonywania mogą pojawić się dalsze optymalizacje. Przechodzę tylko przez to, co zostało wyprodukowane przez IL.
Wreszcie, jeśli chodzi o internowanie, stałe i literały są internowane, ale wartość, która jest internowana, jest wynikową stałą wartością w IL, a nie literałem. Oznacza to, że możesz otrzymać nawet mniej obiektów łańcuchowych, niż się spodziewasz, ponieważ wiele identycznie zdefiniowanych stałych lub literałów będzie w rzeczywistości tym samym obiektem! Ilustrują to następujące elementy:
W przypadku, gdy ciągi są łączone w pętli (lub w inny sposób dynamicznie), otrzymujesz jeden dodatkowy ciąg na konkatenację. Na przykład poniższy rysunek tworzy 12 instancji ciągu: 2 stałe + 10 iteracji, z których każda daje nową instancję ciągu:
Jednak (co jest również zaskakujące), kompilator łączy wiele kolejnych konkatenacji w jedną konkatenację z wieloma ciągami. Na przykład ten program również tworzy tylko 12 instancji łańcuchów! Dzieje się tak, ponieważ „ Nawet jeśli używasz kilku operatorów + w jednej instrukcji, treść ciągu jest kopiowana tylko raz ”.
źródło
string s = ""; for (int i = 0; i < n; i++) s += "a";
Odpowiedź Chrisa Shaina jest bardzo dobra. Jako osoba, która napisała optymalizator konkatenacji ciągów, dodałbym tylko dwa dodatkowe interesujące punkty.
Po pierwsze, optymalizator konkatenacji zasadniczo ignoruje zarówno nawiasy, jak i lewe skojarzenie, jeśli może to zrobić bezpiecznie. Załóżmy, że masz metodę M (), która zwraca ciąg. Jeśli powiesz:
następnie kompilator wnioskuje, że operator dodawania jest pozostawiony asocjacyjny, a zatem jest to to samo, co:
Ale to:
jest taki sam jak
więc to jest konkatenacja stałego ciągu
"CD"
zM()
.W rzeczywistości optymalizator konkatenacji zdaje sobie sprawę, że konkatenacja ciągów jest asocjacyjna i generuje
String.Concat(M(), "AB")
dla pierwszego przykładu, nawet jeśli narusza to lewe skojarzenie.Możesz nawet to zrobić:
i nadal będziemy generować
String.Concat(M(), "EF", M())
.Drugim interesującym punktem jest to, że puste i puste ciągi są zoptymalizowane. Więc jeśli to zrobisz:
dostaniesz
String.Concat(M(), M())
Pojawia się wtedy interesujące pytanie: co z tym?
Nie możemy tego zoptymalizować do
ponieważ
M()
może zwrócić wartość null, aleString.Concat(M(), null)
zwróci pusty ciąg, jeśliM()
zwróci wartość null. Więc zamiast tego zmniejszamydo
W ten sposób wykazanie, że konkatenacja ciągów nie musi w rzeczywistości
String.Concat
w ogóle wywoływać .Więcej informacji na ten temat znajdziesz w
Dlaczego String.Concat nie jest zoptymalizowany do StringBuilder.Append?
źródło
("C" + "D") + M())
generujeString.Concat("CD", M())
, a nieString.Concat(M(), "AB")
. A niżej(M() + "E") + (null + M())
powinien generowaćString.Concat(M(), "E", M())
, a nieString.Concat(M(), M())
.Znalazłem odpowiedź w MSDN. Jeden.
Instrukcje: łączenie wielu ciągów (przewodnik programowania w języku C #)
źródło
Tylko jeden. Kompilator C # zwinie stałe ciągów i dlatego zasadniczo kompiluje się do
źródło
Wątpię, czy jest to wymagane przez jakąkolwiek normę lub specyfikację. Jedna wersja może prawdopodobnie robić coś innego niż inna.
źródło
Po pierwsze, ponieważ są statyczne, kompilator będzie w stanie zoptymalizować je do pojedynczego ciągu w czasie kompilacji.
Gdyby były dynamiczne, zostałyby zoptymalizowane pod kątem pojedynczego wywołania String.Concat (string, string, string, string) .
źródło