Могу ли я применить атрибут к унаследованному члену? - PullRequest
8 голосов
/ 24 июня 2009

Предположим, у меня есть следующий (тривиально простой) базовый класс:

public class Simple
{
    public string Value { get; set; }
}

Теперь я хочу сделать следующее:

public class PathValue : Simple
{
    [XmlAttribute("path")]
    public string Value { get; set; }
}

public class ObjectValue : Simple
{
    [XmlAttribute("object")]
    public string Value { get; set; }
}

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

Реальная проблема заключается в том, что в моем механизме сериализации из / в XML (который прекрасно работает, кстати), я нахожу много похожих элементов, где отличаются только имена атрибутов (они не согласованы, и я не контролировать формат). Сейчас мне нужно создать разные классы для каждого такого элемента, тогда как они похожи на 100% одинаковые (кроме атрибутов).

Не думаю, что это возможно, но вы никогда не узнаете.

UPDATE:

Я попробовал подход Марка, но безрезультатно:

public class Document
{
    public PathValue Path;
    public ObjectValue Object;
}

class Program
{
    static void Main(string[] args)
    {
        var doc = new Document()
        {
            Path = new PathValue() { Value = "some path" },
            Object = new ObjectValue() { Value = "some object" }
        };

        XmlAttributeOverrides overrides = new XmlAttributeOverrides();

        overrides.Add(typeof(PathValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("path") });
        overrides.Add(typeof(ObjectValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("object") });

        XmlSerializer serializer = new XmlSerializer(typeof(Document), overrides);

        serializer.Serialize(Console.Out, doc);

        Console.WriteLine();
        Console.ReadLine();
    }
}

... не работает.

Ответы [ 5 ]

5 голосов
/ 16 сентября 2009

Я собираюсь ответить на этот вопрос сам, чтобы я мог принять этот ответ. Мне не нравится ответ, но я полагаю, что это единственный правильный ответ.

Ответ: нет, вы не можете этого сделать.

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

Не могли бы вы использовать конструктор перегрузки XmlSerializer, который позволяет передавать атрибуты для применения во время выполнения? Тогда вам не нужно об этом беспокоиться ...

caveat: вы хотите кэшировать экземпляр сериализатора и использовать его повторно; в противном случае (со сложными конструкторами) каждый раз выполняется генерация динамического типа.

Пример:

using System;
using System.Xml.Serialization;
public class Simple {
    public string Value { get; set; }

    static void Main() {
        XmlAttributeOverrides overrides = new XmlAttributeOverrides();
        overrides.Add(typeof(Simple), "Value", new XmlAttributes {
           XmlAttribute = new XmlAttributeAttribute("path")
        });
        XmlSerializer pathSerializer = new XmlSerializer(
            typeof(Simple), overrides);
        // cache and re-use pathSerializer!!!

        Simple obj = new Simple();
        obj.Value = "abc";
        pathSerializer.Serialize(Console.Out, obj);
    }
}

Выход:

<Simple xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" path="abc" />
1 голос
/ 21 июня 2013

Как насчет этого:

public class Simple
{
    [XmlIgnore]
    public string Value { get; set; }
}

public class PathValue : Simple
{
    [XmlAttribute("path")]
    public string Path { 
            get { return base.Value != null ? base.Value : null; }
            set { base.Value = value != null ? value : null; }
    }
}

public class ObjectValue : Simple
{
    [XmlAttribute("object")]
    public string Object { 
            get { return base.Value != null ? base.Value : null; }
            set { base.Value = value != null ? value : null; }
    }
}

Это тот же метод, который используется для сериализации несериализуемого типа, такого как Uri, который принимает сериализуемый тип в конструкторе.

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

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

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

Вы, вероятно, знаете об этом, но как идея (хотя в этом случае структура кода полностью изменится):

Одним из способов было бы сериализовать базовый класс в виде набора пар имя-значение, используя настраиваемую сериализацию (есть также XDocument и аналогичные полезные вещи для упрощения). Хотя он не обеспечивает безопасность типов, он избавит вас от большого количества ручной работы.

Я также предпочитаю использовать пользовательскую сериализацию, поскольку она предоставляет более широкий диапазон возможностей (например, сериализация неизменяемых классов). XmlSerializer также иногда очень неприятен (например, я ненавижу добавлять свойство «MyFieldSpecified» для создания необязательных атрибутов).

...