Я не думаю, что какой-либо из существующих ответов действительно отвечает на вопрос. Фактические отношения между двумя классами являются примером шаблона адаптера .
StringWriter
реализует все свои Write...
методы путем перенаправления на экземпляр StringBuilder
, который он хранит в поле. Это не просто внутренняя деталь, потому что StringWriter
имеет открытый метод GetStringBuilder , который возвращает внутренний строитель строк, а также конструктор , который позволяет вам передать существующий StringBuilder
.
Итак, StringWriter
- это адаптер, который позволяет использовать StringBuilder
в качестве цели кодом, который рассчитан на работу с TextWriter
. С точки зрения базового поведения, между ними явно нечего выбирать ... если только вы не можете измерить накладные расходы на переадресацию вызовов, в этом случае StringWriter
немного медленнее, но это вряд ли будет значительным.
Так почему же они не заставили StringBuilder
реализовать TextWriter
напрямую? Это серая область, потому что цель интерфейса не всегда ясна на первый взгляд.
TextWriter
- это очень почти интерфейс для чего-то, что принимает поток символов. Но у него есть дополнительная складка: свойство, называемое Encoding . Это означает, что TextWriter
является интерфейсом для чего-то, что принимает поток символов , а также преобразует их в байты .
Это бесполезный след в StringWriter
, потому что он не выполняет кодирование. документация гласит:
Это свойство необходимо для некоторых сценариев XML, где заголовок должен
быть написано с кодировкой, используемой StringWriter. это
позволяет коду XML использовать произвольный StringWriter и генерировать
правильный заголовок XML.
Но это не может быть правдой, потому что у нас нет способа указать значение Encoding
для StringWriter
. Свойство всегда имеет значение UnicodeEncoding
. Следовательно, любой код, который проверял бы это свойство для создания заголовка XML, всегда говорил бы utf-16
. Например:
var stringWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringWriter))
xDocument.WriteTo(xmlWriter);
Это создает заголовок:
<?xml version="1.0" encoding="utf-16"?>
Что, если вы использовали File.WriteAllText , чтобы записать свою XML-строку в файл? По умолчанию у вас будет файл utf-8
с заголовком utf-16
.
В таких сценариях было бы безопаснее использовать StreamWriter
и создать его с путем к файлу, либо FileStream
, либо, если вы хотите проверить данные, затем использовать MemoryStream
и, таким образом, получить массив байтов . Все эти комбинации гарантируют, что при кодировании в байтах и при создании заголовка используется одно и то же значение Encoding
в вашем StreamWriter
.
Цель свойства Encoding
состояла в том, чтобы позволить генераторам символьных потоков включать точную информацию о кодировке в сам символьный поток (например, в примере XML; другие примеры включают заголовки электронной почты и т. Д.).
Но, введя StringWriter
, эта связь между генерацией контента и кодированием нарушается, и поэтому такие автоматические механизмы перестают работать и становятся потенциально подверженными ошибкам.
Тем не менее, StringWriter
- это полезный адаптер, если вы осторожны, т. Е. Вы понимаете, что ваш код генерации контента не должен зависеть от бессмысленного значения свойства Encoding
. Но такого рода предостережения обычно связаны с шаблоном адаптера. Часто это своего рода хакерство, позволяющее вам вставить квадратный колышек в круглое отверстие.