Как правильно установить StringBuilder.Capacity при использовании P / Invoke? - PullRequest
7 голосов
/ 30 октября 2010

Должно ли StringBuilder.Capacity быть установлено на максимальное количество символов .NET, независимо от нулевого завершения, или оно должно быть установлено на один уровень выше, чтобы резервировать пространство для нулевого терминатора при использовании P / Invoke.

Естественная реакция заключается в том, что он должен быть установлен на один уровень выше, но похоже, что P / Invoke должен автоматически компенсировать это. На самом деле это действительно задокументировано прямо здесь: http://msdn.microsoft.com/en-US/library/s9ts558h(v=VS.100).aspx

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

StringBuilder sb = new StringBuilder(dotNetChars + 1);
SomeWindowsAPI(sb, sb.Capacity);

Вместо:

StringBuilder sb = new StringBuilder(dotNetChars);
SomeWindowsAPI(sb, sb.Capacity + 1);

(Я понимаю, что некоторые API по-разному обрабатывают параметр размера буфера. Предположим, что API обрабатывает это, что является обязательным, как GetFullPathName: http://msdn.microsoft.com/en-us/library/aa364963(v=VS.85).aspx)

Использование выражения с sb.Capacity непосредственно в вызове API представляется наилучшей практикой во избежание несоответствия. Вопрос в том, правильно ли добавить +1.

Оглянись вокруг. Вы, вероятно, обнаружите, что единственное место, где отображается sb.Capacity + 1, - это документация MSDN.

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

Ответы [ 3 ]

4 голосов
/ 19 ноября 2015

Я понимаю, что у вас уже есть ответы пятилетней давности, но, по моему мнению, они на самом деле не отвечают на вопрос, они в основном отбрасывают потенциальную проблему, не проверяя, является ли это правильным.

MSDNдокументация гарантирует, что маршаллер обеспечит достаточно места для хранения полного Capacity StringBuilder плюс дополнительного нулевого терминатора.Цитирование Маршалинг по умолчанию для строк :

Строковые буферы фиксированной длины

[...]

TheРешением является передача буфера StringBuilder в качестве аргумента вместо строки. StringBuilder может быть разыменован и изменен вызываемым абонентом, если он не превышает емкость StringBuilder .Это может также быть инициализировано к фиксированной длине.Например, если вы инициализируете буфер StringBuilder емкостью N , маршалер предоставляет буфер размером ( N + 1) символов.+1 означает, что неуправляемая строка имеет нулевой терминатор, а StringBuilder - нет.

[...]

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

0 голосов
/ 31 октября 2010

Вероятно, происходит определенное количество программ культа грузов.Кто-то подхватывает привычку, когда его спрашивают о памяти выделить для строк, отвечать «длина + 1» вместо длины.Вместо того, чтобы читать документацию для новых обстоятельств, в которых вас просят о выделении памяти для строк, разработчик просто «ошибается в безопасности» и передает длину +1. Другие, которые читают этот код, выводят то же правило и практикураспространяется.Это не должно быть правильно, чтобы быть переданным от человека человеку, просто разумно вероятно, чтобы быть правильным, и не активно вредным.

0 голосов
/ 31 октября 2010

Внутри конструктора StringBuilder емкость используется следующим образом:

m_ChunkChars = new char[capacity];

Используется вместе с полем m_ChunkLength для определения содержимого StringBuilder. Это описывает только реальные символы, не включая завершающий символ.

Так что ваш ответ + 1 не обязателен.

...