Есть ли способ создать неизменяемый (только для чтения) XDocument? - PullRequest
9 голосов
/ 27 августа 2010

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

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

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

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

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

Ответы [ 3 ]

12 голосов
/ 14 июня 2012

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

Вы можете сделать 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

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

4 голосов
/ 27 августа 2010

Вы можете создать оболочку 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);
        }
    }
}
3 голосов
/ 27 августа 2010

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

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

...