C # XML 직렬화를 수행 할 때 공유 할 것이라고 생각한 몇 가지 문제에 봉착했습니다.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
[XmlRoot("dictionary")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
다른 XML 직렬화가 있습니까?
또 다른 큰 문제는 웹 페이지 (ASP.NET)를 통해 XML을 출력 할 때 nicode Byte-Order Mark 를 포함하고 싶지 않은 것입니다. 물론 BOM을 사용하거나 사용하지 않는 방법은 거의 동일합니다.
XmlTextWriter wr = new XmlTextWriter(stream, new System.Text.Encoding.UTF8);
XmlTextWriter wr = new XmlTextWriter(stream, new System.Text.UTF8Encoding(false))
BOM을 원하지 않음을 나타 내기 위해 명시 적으로 false를 전달할 수 있습니다. Encoding.UTF8
및 UTF8Encoding
.
처음에 3 개의 추가 BOM 바이트는 (0xEFBBBF) 또는 (239187191)입니다.
참조 : http://chrislaco.com/blog/troubleshooting-common-problems-with-the-xmlserializer/
아직 댓글을 달 수 없으므로 Dr8k의 게시물에 댓글을 달고 다시 관찰하겠습니다. 공용 게터/세터 속성으로 노출되고 해당 속성을 통해 직렬화/역 직렬화되는 개인 변수입니다. 우리는 내 오래된 직장에서 항상 그것을했다.
그러나 한 가지 주목할 점은 해당 속성에 로직이 있으면 로직이 실행되므로 직렬화 순서가 실제로 중요하다는 것입니다. 멤버는 코드에서 순서에 따라 암시 적으로로 정렬되지만, 특히 다른 객체를 상속 할 때는 보장 할 수 없습니다. 명백하게 그들을 주문하는 것은 뒤쪽에 고통입니다.
나는 과거에 이것으로 화상을 입었다.
메모리 스트림에서 XML 문자열로 직렬화 할 때는 MemoryStream # GetBuffer () 대신 MemoryStream # ToArray ()를 사용해야합니다.
http://msdn.Microsoft.com/en-us/library/system.io.memorystream.getbuffer (VS.80) .aspx
수익률 반환을 통해 생성 된 IEnumerables<T>
는 직렬화 할 수 없습니다. 컴파일러는 수율 반환을 구현하기 위해 별도의 클래스를 생성하고 해당 클래스는 직렬화 가능으로 표시되지 않기 때문입니다.
시리얼 라이저에 유형의 인터페이스가있는 멤버/프로퍼티가 있으면 직렬화되지 않습니다. 예를 들어, 다음은 XML로 직렬화되지 않습니다.
public class ValuePair
{
public ICompareable Value1 { get; set; }
public ICompareable Value2 { get; set; }
}
이것은 직렬화되지만 :
public class ValuePair
{
public object Value1 { get; set; }
public object Value2 { get; set; }
}
읽기 전용 속성을 직렬화 할 수 없습니다. 역 직렬화를 사용하여 XML을 객체로 변환하지 않더라도 getter 및 setter가 있어야합니다.
같은 이유로 인터페이스를 반환하는 속성을 serialize 할 수 없습니다. deserializer는 인스턴스화 할 구체적인 클래스를 알지 못합니다.
오 좋은 점이 있습니다. XML 직렬화 코드가 생성되어 별도의 DLL에 배치되므로 코드에 직렬 변환기를 손상시키는 실수가 있어도 의미있는 오류가 발생하지 않습니다. "s3d3fsdf.dll을 (를) 찾을 수 없음"과 같은 것입니다. 좋은.
매개 변수가없는 construtor가없는 객체를 직렬화 할 수 없습니다 (그냥 물린 것).
그리고 어떤 이유로 다음 속성에서 Value가 serialize되지만 FullName은 직렬화되지 않습니다.
public string FullName { get; set; }
public double Value { get; set; }
나는 왜 그 일을 끝내지 못했는지, 방금 Value를 내부로 변경했습니다 ...
"기본"XML 직렬화를 사용하는 경우 개인/보호 된 클래스 멤버를 직렬화 할 수 없습니다.
그러나 클래스에서 IXmlSerializable을 구현하는 사용자 정의 XML 직렬화 논리를 지정하고 필요/원하는 개인 필드를 직렬화 할 수 있습니다.
http://msdn.Microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
Color 및/또는 Font 유형의 개체를 직렬화하는 데 문제가 발생할 수 있습니다.
여기 도움이 된 조언이 있습니다.
http://www.codeproject.com/KB/XML/xmlsettings.aspx
http://www.codeproject.com/KB/cs/GenericXmlSerializition.aspx
XML Serializer가 지원하는 내용 및 지원되는 XSD 기능이 지원되는 방법에 대한 자세한 내용은 " 고급 XML 스키마 정의 언어 속성 바인딩 지원 "을 참조하십시오.
List<T>
또는 subclassesT
의 인스턴스를 포함하는 IEnumerable<T>
을 직렬화하려는 경우 다음을 수행해야합니다. 사용되는 모든 하위 유형을 나열하려면 XmlArrayItemAttribute 를 사용하십시오. 그렇지 않으면 직렬화 할 때 런타임에 도움이되지 않는 System.InvalidOperationException
이 표시됩니다.
다음은 문서 의 전체 예제 중 일부입니다.
public class Group
{
/* The XmlArrayItemAttribute allows the XmlSerializer to insert both the base
type (Employee) and derived type (Manager) into serialized arrays. */
[XmlArrayItem(typeof(Manager)), XmlArrayItem(typeof(Employee))]
public Employee[] Employees;
XML 직렬화로 생성 된 어셈블리가이를 사용하려는 코드와 동일한로드 컨텍스트에없는 경우 다음과 같은 멋진 오류가 발생합니다.
System.InvalidOperationException: There was an error generating the XML document.
---System.InvalidCastException: Unable to cast object
of type 'MyNamespace.Settings' to type 'MyNamespace.Settings'. at
Microsoft.Xml.Serialization.GeneratedAssembly.
XmlSerializationWriterSettings.Write3_Settings(Object o)
이 문제의 원인은 LoadFrom context 를 사용하여로드 된 플러그인이므로 Load 컨텍스트를 사용하는 데 많은 단점이 있습니다. 그 중 하나를 추적하는 것은 꽤 재미있는 일입니다.
Obsolete
특성으로 표시된 속성은 직렬화되지 않습니다. Deprecated
속성으로 테스트하지는 않았지만 같은 방식으로 작동한다고 가정합니다.
개인 변수/속성은 XML 직렬화의 기본 메커니즘에서 직렬화되지 않지만 2 진 직렬화입니다.
XSD가 대체 그룹을 사용하는 경우 자동으로 직렬화를 해제 할 수 없습니다. 이 시나리오를 처리하려면 고유 한 직렬 변환기를 작성해야합니다.
예 :.
<xs:complexType name="MessageType" abstract="true">
<xs:attributeGroup ref="commonMessageAttributes"/>
</xs:complexType>
<xs:element name="Message" type="MessageType"/>
<xs:element name="Envelope">
<xs:complexType mixed="false">
<xs:complexContent mixed="false">
<xs:element ref="Message" minOccurs="0" maxOccurs="unbounded"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="ExampleMessageA" substitutionGroup="Message">
<xs:complexType mixed="false">
<xs:complexContent mixed="false">
<xs:attribute name="messageCode"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="ExampleMessageB" substitutionGroup="Message">
<xs:complexType mixed="false">
<xs:complexContent mixed="false">
<xs:attribute name="messageCode"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
이 예에서 봉투에는 메시지가 포함될 수 있습니다. 그러나 .NET의 기본 직렬 변환기는 Message, ExampleMessageA 및 ExampleMessageB를 구분하지 않습니다. 기본 Message 클래스와 만 직렬화됩니다.
명시적인 직렬화없이 형식을 신중하게 직렬화하면 .Net이 빌드하는 동안 지연 될 수 있습니다. 최근에 이것을 발견했습니다 RSAParameters를 직렬화하는 동안 .
나는 이것을 정말로 설명 할 수는 없지만 이것이 직렬화되지는 않는다는 것을 알았다.
[XmlElement("item")]
public myClass[] item
{
get { return this.privateList.ToArray(); }
}
그러나 이것은 :
[XmlElement("item")]
public List<myClass> item
{
get { return this.privateList; }
}
또한 memstream으로 직렬화하는 경우 사용하기 전에 0을 찾고 싶을 수도 있습니다.
개인 변수/속성은 XML 직렬화로 직렬화되지 않지만 이진 직렬화로되어 있습니다.
공개 속성을 통해 비공개 멤버를 노출하는 경우 에도이 정보가 표시됩니다. 비공개 멤버는 직렬화되지 않으므로 공개 멤버가 모두 null 값을 참조합니다.