115 votes

Combien d'objets String seront créés lors de l'utilisation d'un signe plus?

Combien d'objets String seront créés lors de l'utilisation d'un signe plus dans le code ci-dessous?

 String result = "1" + "2" + "3" + "4";
 

Si c'était comme ci-dessous, j'aurais dit trois objets String: "1", "2", "12".

 String result = "1" + "2";
 

Je sais également que les objets String sont mis en cache dans le pool / tableau de stagiaires en chaîne pour améliorer les performances, mais ce n'est pas la question.

161voto

Chris Shain Points 33569

Étonnamment, ça dépend.

Si vous le faites dans une méthode:

void Foo() {
    String one = "1";
    String two = "2";
    String result = one + two + "34";
    Console.Out.WriteLine(result);
}

ensuite, le compilateur semble émettre le code à l'aide d' String.Concat @Joachim de réponse (+1 pour lui d'ailleurs).

Si vous les définissez comme des constantes, par exemple:

const String one = "1";
const String two = "2";
const String result = one + two + "34";

ou littéraux, comme dans la question d'origine:

String result = "1" + "2" + "3" + "4";

ensuite, le compilateur d'optimiser loin de ces + signes. C'est l'équivalent de:

const String result = "1234";

En outre, le compilateur va supprimer étrangères des expressions constantes, et n'émettent que s'ils sont utilisés ou exposés. Par exemple, ce programme:

const String one = "1";
const String two = "1";
const String result = one + two + "34";

public static void main(string[] args) {
    Console.Out.WriteLine(result);
}

Seulement génère une chaîne de caractères - la constante result (égal à "1234"). one et two n'apparaissent pas dans le résultat de l'ILLINOIS.

Gardez à l'esprit qu'il peut y avoir d'autres optimisations lors de l'exécution. Je vais juste par ce qu'IL est produit.

Enfin, en ce qui concerne la formation, les constantes et les littéraux sont internés, mais la valeur qui est internée est la résultante de la valeur de la constante dans l'IL, pas au sens littéral. Cela signifie que vous pouvez obtenir encore moins des objets de chaîne que vous attendez, depuis plusieurs du même défini des constantes ou des littéraux sera effectivement le même objet! Ceci est illustré par le texte suivant:

public class Program
{
    private const String one = "1";
    private const String two = "2";
    private const String RESULT = one + two + "34";

    static String MakeIt()
    {
        return "1" + "2" + "3" + "4";
    }   

    static void Main(string[] args)
    {
        string result = "1" + "2" + "34";

        // Prints "True"
        Console.Out.WriteLine(Object.ReferenceEquals(result, MakeIt()));

        // Prints "True" also
        Console.Out.WriteLine(Object.ReferenceEquals(result, RESULT));
        Console.ReadKey();
    }
}

Dans le cas où les Chaînes sont concaténées dans une boucle (ou sinon de façon dynamique), vous vous retrouvez avec une chaîne par concaténation. Par exemple, le code suivant crée à 12 cordes instances: 2 constantes de + 10 itérations, chacune aboutissant à une nouvelle Chaîne de caractères exemple:

public class Program
{
    static void Main(string[] args)
    {
        string result = "";
        for (int i = 0; i < 10; i++)
            result += "a";
        Console.ReadKey();
    }
}

Mais (aussi, étonnamment), de multiples consécutifs concaténations sont combinées par le compilateur en un seul multi-concaténation de chaîne. Par exemple, ce programme ne produit que 12 des instances de chaîne! C'est parce que "Même si vous utilisez plusieurs + opérateurs dans une déclaration, la chaîne de contenu est copié qu'une seule fois."

public class Program
{
    static void Main(string[] args)
    {
        string result = "";
        for (int i = 0; i < 10; i++)
            result += "a" + result;
        Console.ReadKey();
    }
}

85voto

Eric Lippert Points 300275

Chris Shain réponse est très bonne. Comme la personne qui a écrit la concaténation de chaîne optimiseur, je voudrais juste ajouter deux autres points intéressants.

La première est que la concaténation de l'optimiseur ignore le plus souvent les deux parenthèses et associativité gauche quand il peut le faire en toute sécurité. Supposons que vous avez une méthode M() qui retourne une chaîne de caractères. Si vous dites:

string s = M() + "A" + "B";

ensuite, le compilateur raisons que l'opérateur d'addition est associativité à gauche, et, par conséquent, c'est la même chose que:

string s = ((M() + "A") + "B");

Mais ce:

string s = "C" + "D" + M();

est le même que

string s = (("C" + "D") + M());

donc, c'est la concaténation de la chaîne constante "CD" avec M().

En fait, la concaténation de l'optimiseur se rend compte que la concaténation de chaîne est associative, et génère String.Concat(M(), "AB") pour le premier exemple, même si cela viole associativité gauche.

Vous pouvez même le faire:

string s = (M() + "E") + ("F" + M()));

et nous allons continuer à générer String.Concat(M(), "EF", M()).

Le deuxième point intéressant est que la valeur null et des chaînes vides sont optimisés à l'écart. Donc, si vous faites cela:

string s = (M() + "") + (null + M());

vous obtiendrez String.Concat(M(), M())

Une question intéressante est alors posée: à quoi à ce sujet?

string s = M() + null;

On ne peut pas optimiser à

string s = M();

parce qu' M() peut retourner null, mais String.Concat(M(), null) serait renvoie une chaîne vide si M() renvoie la valeur null. Donc ce que nous faisons est de réduire

string s = M() + null;

pour

string s = M() ?? "";

Ce qui démontre que la concaténation de chaîne n'a pas besoin de communiquer String.Concat .

Pour de plus amples informations sur ce sujet, voir

Pourquoi est-Chaîne.Concat pas optimisé pour StringBuilder.Ajouter?

23voto

David Stratton Points 45298

J'ai trouvé la réponse sur le site MSDN. Un.

Comment: Concaténer Plusieurs Chaînes de caractères (Guide de Programmation C#)

La concaténation est le processus d'ajout d'une chaîne à la fin de une autre chaîne. Lorsque vous concaténer des chaînes de caractères littérales ou chaîne les constantes en utilisant l'opérateur+, le compilateur crée un seul chaîne de caractères. Aucun moment de l'exécution de concaténation se produit. Cependant, les variables de chaîne peuvent être concaténés seulement au moment de l'exécution. Dans ce cas, vous devez comprendre les implications sur les performances des différentes approches.

22voto

JaredPar Points 333733

Juste un. Le compilateur C # va plier les constantes de chaîne et par conséquent, il compile essentiellement jusqu'à

 String result = "1234";
 

13voto

Joachim Isaksson Points 85969

Un, car ils sont statiques, le compilateur sera capable de l’optimiser en une seule chaîne au moment de la compilation.

S'ils avaient été dynamiques, ils auraient été optimisés pour un seul appel à String.Concat (chaîne, chaîne, chaîne, chaîne) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X