Есть ли способ создать неизменяемый (только для чтения) 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 для того, что он хочет. Конец всего этого будет сделать файл доступным только для чтения на диске и убедиться, что у них (разработчиков, пользователей) нет прав на изменение доступа к файлу только для чтения.