이는 형식 정보가 출력에 포함되지 않는 선언적 직렬화의 내재 된 제한 일뿐입니다.
<Flibble Foo="10" />
다시 변환하려고 할 때
public class Flibble { public object Foo { get; set; } }
serializer는 그것이 int, string, double (또는 다른 것)인지 어떻게 알 수 있습니까?
이 작업을 수행하려면 몇 가지 옵션이 있지만 런타임까지 진정으로 모르는 경우 가장 쉬운 방법은 다음을 사용하는 것입니다. XmlAttributeOverrides를 입니다.
슬프게도 이것은 인터페이스가 아닌 기본 클래스에서만 작동합니다. 당신이 할 수있는 최선은 당신의 필요에 충분하지 않은 재산을 무시하는 것입니다.
인터페이스를 유지해야한다면 세 가지 실제 옵션이 있습니다.
그것을 숨기고 다른 재산에서 처리하십시오
추악하고 불쾌한 보일러 플레이트와 많은 반복이지만 클래스의 대부분의 소비자는 문제를 다룰 필요가 없습니다.
[XmlIgnore()]
public object Foo { get; set; }
[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized
{
get { }
set { }
}
이것은 유지 관리의 악몽이 될 가능성이 높습니다 ...
IXmlSerializable 구현
모든 것을 제어 할 수 있다는 점에서 첫 번째 옵션과 유사하지만
- 장점
- 당신은 주변에 거슬리는 '가짜'속성이 없습니다.
- 유연성 / 버전 관리를 추가하는 xml 구조와 직접 상호 작용할 수 있습니다.
- 단점
- 클래스의 다른 모든 속성에 대해 휠을 다시 구현해야 할 수도 있습니다.
노력의 중복 문제는 첫 번째 문제와 유사합니다.
래핑 유형을 사용하도록 속성 수정
public sealed class XmlAnything<T> : IXmlSerializable
{
public XmlAnything() {}
public XmlAnything(T t) { this.Value = t;}
public T Value {get; set;}
public void WriteXml (XmlWriter writer)
{
if (Value == null)
{
writer.WriteAttributeString("type", "null");
return;
}
Type type = this.Value.GetType();
XmlSerializer serializer = new XmlSerializer(type);
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
serializer.Serialize(writer, this.Value);
}
public void ReadXml(XmlReader reader)
{
if(!reader.HasAttributes)
throw new FormatException("expected a type attribute!");
string type = reader.GetAttribute("type");
reader.Read();
if (type == "null")
return;
XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
this.Value = (T)serializer.Deserialize(reader);
reader.ReadEndElement();
}
public XmlSchema GetSchema() { return(null); }
}
이것을 사용하면 (프로젝트 P에서) 다음과 같은 것이 관련됩니다.
public namespace P
{
public interface IFoo {}
public class RealFoo : IFoo { public int X; }
public class OtherFoo : IFoo { public double X; }
public class Flibble
{
public XmlAnything<IFoo> Foo;
}
public static void Main(string[] args)
{
var x = new Flibble();
x.Foo = new XmlAnything<IFoo>(new RealFoo());
var s = new XmlSerializer(typeof(Flibble));
var sw = new StringWriter();
s.Serialize(sw, x);
Console.WriteLine(sw);
}
}
다음을 제공합니다.
<?xml version="1.0" encoding="utf-16"?>
<MainClass
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<RealFoo>
<X>0</X>
</RealFoo>
</Foo>
</MainClass>
이것은 많은 보일러 플레이트를 피하지만 클래스 사용자에게는 분명히 더 번거 롭습니다.
행복한 매체는 XmlAnything 아이디어를 첫 번째 기술의 'backing'속성에 병합하는 것일 수 있습니다. 이런 식으로 대부분의 지저분한 작업이 당신을 위해 이루어 지지만 동급의 소비자는 자기 성찰과의 혼동 이상의 영향을받지 않습니다.