Функция для создания дерева свойств? - PullRequest
0 голосов
/ 06 октября 2010

Я пытаюсь создать список свойств для объектов. Я могу просто создать список для базовых объектов, но если у меня есть ситуация, когда объект типа A содержит свойство объекта типа B, которое содержит свойство объекта типа A .... ну ... тогда я получаю бесконечную рекурсию. Я добавил статическое свойство ко всем моим объектам под названием «RecursivePropertyList», которое представляет собой List<string> каждого свойства, имеющего рекурсию.

Так, например: У меня есть класс Person со свойством Vendor типа Vendor. Класс Vendor имеет свойство с именем People типа List<Person>.

В классе Person я устанавливаю значение RecursivePropertyList равным myList.Add("Vendor.People"). В классе Vendor я установил значение RecursivePropertyList равным myList.Add("People.Vendor").

Затем в моей функции, которая создает список свойств, я проверяю, находится ли текущее имя_объекта.propertyName в RecursivePropertyList, и если это так, я не добавляю его в свой список свойств и не раскрываю в него, чтобы получить его свойства.

Это прекрасно работает в ситуации, описанной выше.

Однако, он начинает терпеть неудачу, когда у меня возникает следующая ситуация: Application класс со свойством типа List<ApplicationFunction_Application>. Класс ApplicationFunction со свойством типа List<ApplicationFunction_Application>. Класс ApplicationFunction_Application, который имеет два свойства, одно из которых типа Application, а другое типа ApplicationFunction. Цель класса ApplicationFunction_Application - определить отношение «многие ко многим» между Application и ApplicationFunction.

В RecursivePropertyList из Application я положил:

myList.Add("ApplicationFunctions.Application");

В RecursivePropertyList из ApplicationFunction я положил:

myList.Add("Applications.ApplicationFunction");

В RecursivePropertyList из ApplicationFunction_Application я положил:

myList.Add("ApplicationFunction.Applications");

myList.Add("Application.ApplicationFunctions");

Но мой сценарий постоянно повторяется и никогда не останавливается.

Вот код, используемый функцией:

Сначала вызывается функция, которая начинает все это:

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList)
        {
            List<string> myRecursivePropertyList = FillDefaultRecursivePropertyList(myObjectType);
            return FillPropertyStateList(myObjectType, ref myPropertyStateList, string.Empty, string.Empty, myRecursivePropertyList);
        }

Затем функция, выполняющая основную часть работы и рекурсивно вызывающая себя для генерации списка свойств для всех дочерних объектов.

public static EquatableList<PropertyState> FillPropertyStateList(System.Type myObjectType, ref EquatableList<PropertyState> myPropertyStateList, string myParentPrefix, string myObjectName, List<string> myRecursivePropertyList)
        {
            if (myPropertyStateList == null)
            {
                myPropertyStateList = new EquatableList<PropertyState>();
            }
            if (string.IsNullOrEmpty(myParentPrefix))
            {
                myParentPrefix = string.Empty;
            }
            else if (!myParentPrefix.EndsWith("."))
            {
                myParentPrefix = myParentPrefix + ".";
            }
            if (string.IsNullOrEmpty(myObjectName))
            {
                myObjectName = string.Empty;
            }
            else
            {
                myObjectName = myObjectName + ".";
            }

            foreach (System.Reflection.PropertyInfo info in myObjectType.GetProperties())
            {
                if (info.PropertyType.BaseType == typeof(BOBase))
                {
                    if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); }))
                    {
                        myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBase));
                        List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType);
                        myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); }));
                        FillPropertyStateList(info.PropertyType, ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList);
                    }
                }
                else if (info.PropertyType.IsGenericType
                    && (info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(List<>) || info.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(Library.EquatableList<>)))
                {
                    if (!myRecursivePropertyList.Exists(delegate(string x) { return x.Equals(myObjectName + info.Name); }))
                    {
                        myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.BOBaseCollection));
                        List<string> myChildRecursivePropertyList = FillDefaultRecursivePropertyList(info.PropertyType.BaseType.GetGenericArguments()[0]);
                        myChildRecursivePropertyList.AddRange(myRecursivePropertyList.FindAll(delegate(string x) { return Regex.IsMatch(x, info.Name + ".*"); }));
                        FillPropertyStateList(info.PropertyType.BaseType.GetGenericArguments()[0], ref myPropertyStateList, myParentPrefix + myObjectName, info.Name, myChildRecursivePropertyList);
                    }
                }
                else
                {
                    myPropertyStateList.Add(new PropertyState(myParentPrefix + myObjectName + info.Name, true, PropertyType.Standard));
                }

            }
            return myPropertyStateList;
        }

Вспомогательная функция, которая получает список рекурсивных свойств по умолчанию:

private static List<string> FillDefaultRecursivePropertyList(System.Type myObjectType)
    {
        List<string> myRecursivePropertyList = new List<string>();
        if (myObjectType.BaseType == typeof(BOBase))
        {
            System.Reflection.PropertyInfo pi = myObjectType.GetProperty("RecursivePropertyList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
            if (pi != null)
            {
                myRecursivePropertyList = (List<string>)pi.GetValue(null, null);
            }
        }
        return myRecursivePropertyList;
    }

Есть идеи, что я делаю не так?

1 Ответ

0 голосов
/ 06 октября 2010

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

ETA: Пример кода:

Если я правильно понимаю, что-то подобное будет работать для свойстваатрибут уровня.Он включает вспомогательный метод для извлечения свойств, помеченных как рекурсивные, из данного типа, что может помочь при построении дерева.

[AttributeUsage(AttributeTargets.Property)]
public class RecursivePropertyAttribute
    : Attribute
{
    private static Dictionary<Type, List<PropertyInfo>> _Cache = new Dictionary<Type, List<PropertyInfo>>();

    public IEnumerable<PropertyInfo> GetRecursiveProperties(Type t)
    {
        // Check the cache for the type
        if (!_Cache.ContainsKey(t))
        { 
            // Create the entry
            _Cache.Add(t, new List<PropertyInfo>());

            // Add properties that have the attribute
            foreach (PropertyInfo p in t.GetProperties())
            {
                if (p.IsDefined(typeof(RecursivePropertyAttribute), true))
                    _Cache[t].Add(p);
            }
        }

        return _Cache[t];
    }
}
...