Подтвердить что ты не робот

Есть ли какой-либо штраф между добавочной строкой vs char в С#

При разработке в Java пару лет назад я узнал, что лучше добавить char, если бы у меня был один символ вместо строки с одним символом, потому что виртуальной машине не пришлось бы искать какой-либо поиск в строке значение в его внутреннем пуле строк.

string stringappend = "Hello " + name + "."; 
string charappend = "Hello " + name + '.'; // better?

Когда я начал программировать на С#, я никогда не думал о вероятности того, что он будет таким же, как и с его "VM". Я столкнулся с С# String Theory-String intern pool, в котором указано, что С# также имеет внутренний пул строк (я думаю, это было бы странно, если бы оно не было" t), поэтому мой вопрос:

Есть ли вообще какие-либо преимущества при добавлении char вместо строки при конкатенации строки относительно С# или это просто jibberish?

Изменить: Пожалуйста, не обращайте внимания на StringBuilder и string.Format, меня больше интересует, почему я бы заменил ".". с '.' в коде. Я хорошо знаю эти классы и функции.

4b9b3361

Ответ 1

Если вы дадите выбор, я бы передал string, а не char при вызове System.String.Concat или (эквивалентном) +.

Единственные перегрузки, которые я вижу для System.String.Concat, принимают либо строки, либо объекты. Поскольку char не является строкой, будет выбрана версия объекта. Это приведет к коробке char. После того, как Concat проверяет, что ссылка на объект не равна null, он затем вызывает object.ToString в char. Затем он создавал бы страшную односимвольную строку, которой в первую очередь избегали, прежде чем создавать новую конкатенацию.

Итак, я не вижу, как прохождение char будет что-то набирать.

Возможно, кто-то хочет посмотреть операцию Concat в Reflector, чтобы увидеть, есть ли специальная обработка для char?

UPDATE

Как я думал, этот тест подтверждает, что char немного медленнее.

using System;
using System.Diagnostics;

namespace ConsoleApplication19
{
    class Program
    {
        static void Main(string[] args)
        {
            TimeSpan throwAwayString = StringTest(100);
            TimeSpan throwAwayChar = CharTest(100);
            TimeSpan realStringTime = StringTest(10000000);
            TimeSpan realCharTime = CharTest(10000000);
            Console.WriteLine("string time: {0}", realStringTime);
            Console.WriteLine("char time: {0}", realCharTime);
            Console.ReadLine();
        }

        private static TimeSpan StringTest(int attemptCount)
        {
            Stopwatch sw = new Stopwatch();
            string concatResult = string.Empty;
            sw.Start();
            for (int counter = 0; counter < attemptCount; counter++)
                concatResult = counter.ToString() + ".";
            sw.Stop();
            return sw.Elapsed;
        }

        private static TimeSpan CharTest(int attemptCount)
        {
            Stopwatch sw = new Stopwatch();
            string concatResult = string.Empty;
            sw.Start();
            for (int counter = 0; counter < attemptCount; counter++)
                concatResult = counter.ToString() + '.';
            sw.Stop();
            return sw.Elapsed;
        }
    }
}

Результаты:

string time: 00:00:02.1878399
char time: 00:00:02.6671247

Ответ 2

При разработке в Java пару лет назад я узнал, что лучше добавить char, если бы у меня был один символ вместо строки с одним символом, потому что виртуальной машине не пришлось бы искать какой-либо поиск в строке значение в его внутреннем пуле строк.

Добавление char в String скорее всего будет немного быстрее, чем добавление 1 символа String, потому что:

  • Операции append(char) не нужно загружать строку length,
  • ему не нужно загружать ссылку на массив characters,
  • ему не нужно загружать и добавлять смещение строки start,
  • ему не нужно выполнять проверку границ в индексе массива, а
  • ему не нужно увеличивать и проверять переменную цикла.

Взгляните на исходный код Java для String и связанных классов. Вы можете быть удивлены, что происходит под капотом.

Внутренний пул не имеет к этому никакого отношения. Интернирование строковых литералов происходит только один раз во время загрузки класса. Интернирование нелитерарных строк происходит только в том случае, если приложение явно вызывает String.intern().

Ответ 3

Это может быть интересно: http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx

Stringbuilder не обязательно быстрее, чем строки, это, как сказано ранее, зависит. Это зависит от конфигурации машины, доступной памяти и мощности процессора, версии каркаса и конфигурации машины. Ваш профилировщик - ваш лучший друг в этом случае:)

Назад 2 Тема: Вы должны просто ПРОДОЛЖИТЬ, что быстрее. Сделайте эту конкатенацию огромным количеством раз, и пусть ваш профилер смотрит. Вы увидите возможные различия.

Ответ 4

Вся конкатенация строк в .NET(со стандартными операторами i.e. +) требует, чтобы среда выполнения сохраняла достаточную память для полной новой строки для хранения результатов конкатенации. Это связано с тем, что тип строки является неизменным.

Если вы выполняете конкатенацию строк много раз (т.е. внутри цикла и т.д.), вы будете испытывать проблемы с производительностью (и, в конечном итоге, проблемы с памятью, если строка достаточно велика), так как среда выполнения .NET должна постоянно выделять и освобождать память для хранения каждой новой строки.

Вероятно, по этой причине вы думаете (правильно), что чрезмерная конкатенация строк может быть проблематичной. У него очень мало (если что-либо) сделать с конкатенированием char, а не с типом строки.

Альтернативой этому является использование класса StringBuilder в пространстве имен System.Text. Этот класс представляет собой изменяемый объект, похожий на строку, который может использоваться для объединения строк без значительных проблем с производительностью. Это связано с тем, что класс StringBuilder зарезервирует определенный объем памяти для строки и позволит добавлять конкатенации до конца объема зарезервированной памяти, не требуя полной новой копии всей строки.

EDIT:

Что касается особенностей поиска строк по сравнению с char, я взбивал этот небольшой тест:

class Program
{
    static void Main(string[] args)
    {
        string stringtotal = "";
        string chartotal = "";
        Stopwatch stringconcat = new Stopwatch();
        Stopwatch charconcat = new Stopwatch();
        stringconcat.Start();
        for (int i = 0; i < 100000; i++)
        {
            stringtotal += ".";
        }
        stringconcat.Stop();
        charconcat.Start();
        for (int i = 0; i < 100000; i++)
        {
            chartotal += '.';
        }
        charconcat.Stop();
        Console.WriteLine("String: " + stringconcat.Elapsed.ToString());
        Console.WriteLine("Char  : " + charconcat.Elapsed.ToString());
        Console.ReadLine();
    }
}

Это просто (используя высокопроизводительный StopWatch класс), сколько времени требуется, чтобы объединить 100000 точек/периодов (.) строки типа против 100000 точек/периодов типа char. Я проверил этот тест несколько раз, чтобы предотвратить искажение результатов с одного конкретного прогона, однако каждый раз результаты были похожи на следующие:

String: 00:00:06.4606331
Char  : 00:00:06.4528073

Поэтому, в контексте множественных конкатенаций, я бы сказал, что между этими двумя очень мало различий (по всей вероятности, без разницы при допуске стандартных допусков на тест)

Ответ 5

Я согласен с тем, что все говорят об использовании StringBuilder, если вы делаете много конкатенации строк, потому что String является неизменяемым типом, но не забывайте, что накладные расходы также связаны с созданием класса StringBuilder, поэтому вам придется сделать выбор когда использовать.

В одной из книг Билла Вагнера "Эффект С#" (или может быть во всех трех из них..), он коснулся этого тоже. Вообще говоря, если вам нужно всего лишь добавить несколько фрагментов строк, лучше использовать string.Format, но если вам нужно создать большое строковое значение в потенциально большом цикле, используйте StringBuilder.

Ответ 6

Каждый раз, когда вы объединяете строки с помощью оператора +, среда выполнения создает новую строку, и для избежания этого рекомендуется использовать класс StringBuilder, который имеет метод Append. Вы также можете использовать AppendLine и AppendFormat. Если вы не хотите использовать StringBuilder, вы можете использовать string.Format:

string str = string.Format("Hello {0}.", name);

Ответ 7

Так как строки являются неизменяемыми типами, для этого потребуется создать новый экземпляр строки до того, как значение будет возвращено вам.

Я хотел бы рассмотреть string.Concat(...) для небольшого количества конкатенаций или использовать StringBuilder для многих конкатенаций строк.

Ответ 8

Я не могу говорить с С#, но в Java главное преимущество - это не компиляция, а выигрыш во время выполнения.

Да, если вы используете String, то во время компиляции Java придется искать String во внутреннем пуле и, возможно, создать новый объект String. Но это происходит один раз, во время компиляции, когда вы создаете файлы .class. Пользователь никогда этого не увидит.

То, что пользователь увидит, это то, что во время выполнения, если вы даете символ, программа просто должна получить символ. Готово. Если вы даете String, он должен сначала получить дескриптор объекта String. Затем он должен настроить цикл, чтобы пройти все символы, получить один символ, наблюдать, что больше нет символов, и остановитесь. Я не смотрел на сгенерированный байт-код, но он явно раз за разом работал.