Я пытаюсь десериализовать часть XML, определяющую тип .NET, в экземпляр System.Type. Дано

<SomeObject>
  <SomeType>System.String, mscorlib</SomeType>
</SomeObject>

Десериализовать в класс;

public class SomeObject
{
    public Type SomeType { get; set; }
}

Досадно, что я действительно делал это некоторое время назад, но без доступа к этому исходному коду и неспособности вспомнить, оказалось очень сложно исследовать решение с учетом необходимых ключевых слов («Xml», «Десериализация», «Тип "дает почти все, что есть под солнцем).

Насколько я помню, есть простой Attribute, который я добавляю к свойству SomeType, и XmlSerializer заботится о нем оттуда. Кто-нибудь знает, какой атрибут мне нужен, или я плохо помню?

2
DiskJunky 13 Мар 2018 в 14:10

2 ответа

Лучший ответ

Если вы не хотите иметь дополнительное свойство типа string (обычное решение этой проблемы) - вы можете использовать прокси-класс следующим образом:

public class XmlTypeProxy : IXmlSerializable {
    private string _typeName;

    public XmlTypeProxy() {

    }

    public XmlTypeProxy(string typeName) {
        _typeName = typeName;
    }

    public XmlSchema GetSchema() {
        return null;
    }

    public void ReadXml(XmlReader reader) {
        _typeName = reader.ReadString();
    }

    public void WriteXml(XmlWriter writer) {
        writer.WriteString(_typeName);
    }

    public static implicit operator Type(XmlTypeProxy self) {
        return Type.GetType(self._typeName);
    }

    public static implicit operator XmlTypeProxy(Type self) {
        return new XmlTypeProxy(self.AssemblyQualifiedName);
    }
}

Этот класс просто сохраняет полное имя сборки типа в виде строки и определяет оператор неявного преобразования из и в тип Type. Затем вам просто нужно украсить SomeType атрибутом XmlElement и указать, что Type равно XmlTypeProxy:

public class SomeObject {
    [XmlElement(Type = typeof(XmlTypeProxy))]
    public Type SomeType { get; set; }
}

Теперь, поскольку существует неявное преобразование из Type в XmlTypeProxy (и наоборот) - и сериализация, и десериализация будут работать так, как вы ожидаете.

1
Evk 13 Мар 2018 в 11:30

Хотя я пометил Evk ответ как правильный (и это так, если вы десериализуете более одного {{X0} } свойство), в конце концов я выбрал более простой подход.

Основываясь на этом ответе, я изменил SomeObject на:

public class SomeObject
{
    public string SomeTypeName
    {
        get { return SomeType.AssemblyQualifiedName; }
        set
        {
            var converter = new TypeNameConverter();
            SomeType = (Type)converter.ConvertFrom(value);
        }
    }

    [XmlIgnore]
    public Type SomeType { get; set; }
}

Хотя это более короткий фрагмент кода для одного свойства, он не такой надежный, как принятый ответ. Я записываю здесь два подхода, которые могут помочь другим.

0
DiskJunky 13 Мар 2018 в 16:37