Есть ли способ создать неизменяемый (только для чтения) XDocument?

У меня есть API, который возвращает XElement и я хочу документ, который стоит за этими XElement должен быть неизменным (только для чтения). Мне это нужно для:

  • Не дать разработчикам возможность изменить это случайно:)
  • Улучшение производительности - создание копии XDocument может быть производительность "тяжелой" операции в некоторых случаях.

Кажется невозможным унаследовать и переопределить необходимое поведение в XDocument / XElement / XContainer потому что все виртуальные методы там помечены как internal:

internal virtual void XContainer.AddAttribute(XAttribute a)
{
}

Поэтому мой вопрос - есть ли способ сделать это, или лучше иметь другой API, который либо возвратит что-то вроде XPathNavigator или лучше иметь собственные классы вроде IReadOnlyXElement, так далее.?

3 ответа

Решение

Вы могли бы создать XElement обертка, которая похожа на ReadOnlyCollection<T>,

public sealed class ReadOnlyXElement
{
    private readonly XElement _element;


    public string Value
    {
        get { return _element.Value; }
    }


    public ReadOnlyXElement(XElement element)
    {
        _element = element;
    }


    public IEnumerable<ReadOnlyXElement> Elements()
    {
        foreach (var child in _element.Elements())
        {
            yield return new ReadOnlyXElement(child);
        }
    }

    public IEnumerable<ReadOnlyXElement> Elements(XName xname)
    {
        foreach (var child in _element.Elements(xname))
        {
            yield return new ReadOnlyXElement(child);
        }
    }
}

Я сомневаюсь, что автор все еще ждет ответов, но, возможно, кто-то найдет это полезным.

Вы можете сделать XDocument неизменным, используя событие Changing:

    class Program
    {
        static void Main(string[] args)
        {
            var xdoc = XDocument.Parse("<foo id=\"bar\"></foo>");
            xdoc.Changing += (s, ev) =>
            {
                throw new NotSupportedException("This XDocument is read-only");
            };

            try
            {
                xdoc.Root.Attribute("id").Value = "boo";
            }
            catch (Exception e)
            {
                Console.WriteLine("EXCEPTION: " + e.Message);
            }

            Console.WriteLine("ID on exit: " + xdoc.Root.Attribute("id").Value);

            Console.ReadKey();
        }
    }

// Console output:
// EXCEPTION: This XDocument is read-only
// ID on exit: bar

Не самое хорошее решение, но оно обеспечивает основной механизм, предотвращающий случайные изменения.

ИМХО, вероятно, лучше создать собственный класс-оболочку для взаимодействия с XDocuments/XElements. Затем вы можете ограничить возможность разработчика писать над файлом в коде.

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

Другие вопросы по тегам