Учитывая Объект как таковой
public class Thing
{
public Thing() { this.children = new List<Thing>();}
public int Id {get; set;}
public string Name {get; set;}
public List<Thing> children{ get; set;}
public string ToString(int level = 0)
{
//Level is added purely to add a visual hierarchy
var sb = new StringBuilder();
sb.Append(new String('-',level));
sb.AppendLine($"id:{Id} Name:{Name}");
foreach(var child in children)
{
sb.Append(child.ToString(level + 1));
}
return sb.ToString();
}
}
и, если используется (оскорблен !?) таким образом
public static void Main()
{
var root = new Thing{Id = 1,Name = "Thing1"};
var thing2 = new Thing{Id = 2,Name = "Thing2"};
var thing3 = new Thing{Id = 3,Name = "Thing3"};
root.children.Add(thing2);
thing2.children.Add(thing3);
thing3.children.Add(root); //problem is here
Console.WriteLine(root.ToString());
}
как можно быть Оборонительный о такого рода сценарии.
Этот код в его нынешнем виде создает переполнение стека, бесконечную рекурсию или ошибку превышения памяти .
На веб-сайте (IIS) это приводило к сбою рабочих процессов w3 и, в конечном итоге, к закрытию пула приложений (Rapid-Fail Protection)
Приведенный выше код является ориентировочным только для воспроизведенияэта проблема.В реальном сценарии структура исходит из базы данных с Id и ParentId.
Структура таблицы базы данных похожа на
CREATE TABLE Thing(
Id INT NOT NULL PRIMARY KEY,
Name NVARCHAR(255) NOT NULL,
ParentThingId INT NULL //References self
)
Проблема заключается в том, что создание «вещей» пользователямине препятствует инцестуозным отношениям (то есть, у Родителя могут быть дети (у которых могут быть дети и т. д., которые в конечном итоге снова указывают на родителя). Можно наложить ограничение на БД, чтобы вещь не была его собственным родителем.(имеет смысл), но в зависимости от глубины это может стать уродливым, и есть некоторый аргумент, что может потребоваться циклическая ссылка (мы все еще обсуждаем это ....)
Так что, возможно, структуры могут быть круговыми, но если вы хотите отобразить такую структуру на веб-странице, например, в виде тега <ul><li><a>
в родительском / дочернем меню, как можно превентивно решить проблему с данными, созданными пользователем в коде?
. NET скрипка здесь