Ответ 1
Строки - это UTF-16, поэтому запись в StringWriter всегда будет использовать UTF-16. Если это не то, что вы хотите, используйте другой класс TextWriter
, с нужной кодировкой.
У меня есть этот метод расширения
public static string SerializeObject<T>(this T value)
{
var serializer = new XmlSerializer(typeof(T));
var settings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(true),
Indent = false,
OmitXmlDeclaration = false,
NewLineHandling = NewLineHandling.None
};
using(var stringWriter = new StringWriter())
{
using(var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.Serialize(xmlWriter, value);
}
return stringWriter.ToString();
}
}
но всякий раз, когда я называю это, он имеет кодировку utf-16
, указанную, т.е. <?xml version="1.0" encoding="utf-16"?>
. Что я делаю неправильно?
Строки - это UTF-16, поэтому запись в StringWriter всегда будет использовать UTF-16. Если это не то, что вы хотите, используйте другой класс TextWriter
, с нужной кодировкой.
Насколько я знаю, класс StringWriter всегда будет использовать кодировку UTF 16 при сериализации в строку. Вы можете написать свой собственный класс переопределения, который принимает другую кодировку:
public class StringWriterWithEncoding : StringWriter
{
private readonly Encoding _encoding;
public StringWriterWithEncoding()
{
}
public StringWriterWithEncoding(IFormatProvider formatProvider)
: base(formatProvider)
{
}
public StringWriterWithEncoding(StringBuilder sb)
: base(sb)
{
}
public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider)
: base(sb, formatProvider)
{
}
public StringWriterWithEncoding(Encoding encoding)
{
_encoding = encoding;
}
public StringWriterWithEncoding(IFormatProvider formatProvider, Encoding encoding)
: base(formatProvider)
{
_encoding = encoding;
}
public StringWriterWithEncoding(StringBuilder sb, Encoding encoding)
: base(sb)
{
_encoding = encoding;
}
public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider, Encoding encoding)
: base(sb, formatProvider)
{
_encoding = encoding;
}
public override Encoding Encoding
{
get { return (null == _encoding) ? base.Encoding : _encoding; }
}
}
Итак, вы можете использовать это вместо:
using(var stringWriter = new StringWriterWithEncoding( Encoding.UTF8))
{
...
}
Вы должны получить новый класс из StringWriter, у которого есть свойство избыточной кодировки.
Как говорится в принятом ответе, StringWriter
- это UTF-16 (Unicode) по умолчанию и дизайн. Если вы хотите сделать это, получив в конце строку UTF-8, я могу дать вам два способа сделать это:
Решение № 1 (не очень эффективно, плохая практика, но выполняет свою работу): сбросьте его в текстовый файл и прочитайте обратно, удалите файл (возможно, подходит только для небольших файлов, если вы вообще хотите это сделать) - просто хотел показать, что это можно сделать!)
public static string SerializeObject<T>(this T value)
{
var serializer = new XmlSerializer(typeof(T));
var settings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(true),
Indent = false,
OmitXmlDeclaration = false,
NewLineHandling = NewLineHandling.None
};
using(var xmlWriter = XmlWriter.Create("MyFile.xml", settings))
{
serializer.Serialize(xmlWriter, value);
}
XmlDocument xml = new XmlDocument();
xml.Load("MyFile.xml");
byte[] bytes = Encoding.UTF8.GetBytes(xml.OuterXml);
File.Delete("MyFile.xml");
return Encoding.UTF8.GetString(bytes);
}
Решение № 2 (лучше, проще, более элегантное решение!): Делайте это так, как у вас, с помощью StringWriter
, но используйте его свойство Encoding
чтобы установить его в UTF-8:
public static string SerializeObject<T>(this T value)
{
var serializer = new XmlSerializer(typeof(T));
var settings = new XmlWriterSettings
{
Encoding = new UTF8Encoding(true),
Indent = false,
OmitXmlDeclaration = false,
NewLineHandling = NewLineHandling.None
};
using(var stringWriter = new UTF8StringWriter())
{
using(var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
serializer.Serialize(xmlWriter, value);
}
return stringWriter.ToString();
}
}
public class UTF8StringWriter : StringWriter
{
public override Encoding Encoding
{
get
{
return Encoding.UTF8;
}
}
}
Если вы не хотите использовать класс, производный от StringWriter
, то в вашем случае вы можете просто установить для OmitXmlDeclaration
значение false
и объявить свой собственный, как я делаю ниже:
public static string Serialize<T>(this T value, string xmlDeclaration = "<?xml version=\"1.0\"?>") where T : class, new()
{
if (value == null) return string.Empty;
using (var stringWriter = new StringWriter())
{
var settings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = xmlDeclaration != null,
};
using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
{
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(xmlWriter, value);
var sb = new StringBuilder($"{Environment.NewLine}{stringWriter}");
sb.Insert(0, xmlDeclaration);
return sb.ToString();
}
}
как @john-saunders упомянул в своем ответе:
StringWriter всегда будет использовать UTF-16
Поэтому я использовал MemoryStream для этих целей.
В моем случае я использую кодировку windows-1251.
var xmlSstring = "";
using (var ms = new MemoryStream())
{
var encoding = Encoding.GetEncoding(1251);
var settings = new XmlWriterSettings
{
Indent = true,
Encoding = encoding
};
using (var xmlTextWriter = XmlWriter.Create(ms, settings))
{
doc.Save(xmlTextWriter);
xmlString = encoding.GetString(ms.ToArray());
}
}