Как (xml) сериализовать uri

У меня есть класс, который я обозначил как Serializable, с свойством Uri. Как я могу получить Uri для сериализации/десериализации без создания свойства строки типа?

Ответы

Ответ 1

Основываясь на одном из ответов как сериализовать TimeSpan, я закончил с этим, что хорошо работает для меня и не требует дополнительного свойства:

public class XmlUri : IXmlSerializable
{
    private Uri _Value;

    public XmlUri() { }
    public XmlUri(Uri source) { _Value = source; }

    public static implicit operator Uri(XmlUri o)
    {
        return o == null ? null : o._Value;
    }

    public static implicit operator XmlUri(Uri o)
    {
        return o == null ? null : new XmlUri(o);
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        _Value = new Uri(reader.ReadElementContentAsString());
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteValue(_Value.ToString());
    }
}

Тогда вы можете использовать его так:

public class Settings
{
     public XmlUri Uri { get; set; }
}

...
var s = new Settings { Uri = new Uri("http://www.example.com") };

И он будет красиво сериализоваться и десериализоваться.

Примечание. Невозможно использовать трюк с атрибутом XmlElement(Type = typeof(...)), как указано в другом ответе в связанном выше вопросе, поскольку XmlSerializer проверяет пустой конструктор по умолчанию в исходном типе.

Ответ 2

С помощью XML-сериализатора вы ограничены - он не так универсален, как (скажем) некоторые из параметров binaryformatter/ ISerializable. Один из трюков состоит в том, чтобы иметь второе свойство для сериализации:

[XmlIgnore]
public Uri Uri {get;set;}

[XmlAttribute("uri")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public string UriString {
    get {return Uri == null ? null : Uri.ToString();}
    set {Uri = value == null ? null : new Uri(value);}
}

Два атрибута, доступные для просмотра, скрывают его от представления (но он должен быть включен в общедоступный API для XmlSerializer, чтобы использовать его). XmlIgnore говорит, что не попробовать Uri; и [XmlAttribute(...)] (или [XmlElement(...)]) сообщает ему переименовать UriString, когда (de) сериализует его.

(обратите внимание, что EditorBrowsable применяется только к коду вне сборки, объявляющему тип)

Ответ 3

Для других, кто нашел этот вопрос и кому не понравились решения, существует еще одно гибкое и мощное решение. Это реализация интерфейса IXmlSerializable. Это сложнее, но это того стоит. Вы можете создать любой xml, который вы хотите. Самый простой пример:

public class Product : IXmlSerializable
{
    public string Code { get; set; }

    public string Model { get; set; }

    public string Name { get; set; }

    public Uri ImageUri { get; set; }

    public virtual System.Xml.Schema.XmlSchema GetSchema()
    {
        throw new NotImplementedException();
    }

    public virtual void ReadXml(XmlReader reader)
    {
        reader.MoveToContent();
        Code = reader.GetAttribute("Code");
        Model = reader.GetAttribute("Model");
        Name = reader.GetAttribute("Name");
        if (reader.ReadToDescendant("Image") && reader.HasAttributes)
            ImageUri = new Uri(reader.GetAttribute("Src"));
    }

    public virtual void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("Code", Code);
        writer.WriteAttributeString("Model", Model);
        writer.WriteAttributeString("Name", Name);
        if (ImageUri != null)
        {
            writer.WriteStartElement("Image");
            writer.WriteAttributeString("Src", ImageUri.AbsoluteUri);
            writer.WriteEndElement();
        }
    }
}

И вы получите что-то вроде этого в xml:

<PriceContainer Code="314" Model="PP500" Name="NuTone PurePower PP500 Power Unit">
    <Image Src="http://www.thinkvacuums.com/images/nutone-pp500-activac.jpg" />
</PriceContainer>

Ответ 4

Uri класс реализует ISerializable Интерфейс, чтобы он мог позаботиться о сериализации/десериализации.