Как (XML) сериализовать URI - PullRequest
16 голосов
/ 24 июня 2009

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

Ответы [ 6 ]

32 голосов
/ 24 июня 2009

С сериализатором xml вы ограничены - он не настолько универсален, как, скажем, некоторые из параметров двоичного форматирования / 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, когда (де) сериализует его.

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

12 голосов
/ 18 января 2013

Основываясь на одном из ответов для о том, как сериализовать 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 сначала проверяет пустой конструктор по умолчанию для исходного типа.

1 голос
/ 02 декабря 2015

Для тех, кто нашел этот вопрос и кому не понравились решения, есть другое, более гибкое и мощное решение. Это реализация интерфейса 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>
0 голосов
/ 24 июня 2009

Внедрите и IDeserializationCallback и используйте это поле по своему усмотрению.

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ideserializationcallback.aspx

0 голосов
/ 24 июня 2009

Ури уже Сериализуем, поэтому я не верю, что вы должны что-то делать.

http://msdn.microsoft.com/en-us/library/system.uri(VS.80).aspx

0 голосов
/ 24 июня 2009

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

...