开发者

Function to create a tree of properties?

I am trying to create a List of properties for objects. 开发者_运维技巧 I can create a list for basic objects just fine, but if I have a situation where type object A contains a property of type object B which contains a property of type object A.... well.. then I get infinite recursion. What I've done is added a static property to all of my objects called "RecursivePropertyList" which is a List<string> of each property that has recursion.

So, for example: I have a Person class with a property called Vendor of type Vendor. The Vendor class has a property called People which is of type List<Person>.

In the Person class I set the value of RecursivePropertyList to myList.Add("Vendor.People"). In the Vendor class, I set the value of RecursivePropertyList to myList.Add("People.Vendor").

Then in my function that creates the property list, I check to see if the current objectname.propertyName is in the RecursivePropertyList and if so, I don't add it to my list of properties and don't drill down into it to get its properties.

This works great in the situation described above.

However, it begins to fail when I have the following situation: An Application class that has a property of type List<ApplicationFunction_Application>. An ApplicationFunction class that has a property of type List<ApplicationFunction_Application>. An ApplicationFunction_Application class that has two properties, one of type Application, and another of type ApplicationFunction. The purpose of the ApplicationFunction_Application class is to define a many-to-many relationship between Application and ApplicationFunction.

In the RecursivePropertyList of Application I put:

myList.Add("ApplicationFunctions.Application");

In the RecursivePropertyList of ApplicationFunction I put:

myList.Add("Applications.ApplicationFunction");

In the RecursivePropertyList of ApplicationFunction_Application I put:

myList.Add("ApplicationFunction.Applications");

myList.Add("Application.ApplicationFunctions");

But, my script just keeps looping forever and never stops.

Here is the code used by the function:

First, the function that is called that begins the whole thing:

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);
        }

Then the function that does the meat of the work and that calls itself recursively to generate the property list for all child objects.

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;
        }

The helper function that gets the default recursive properties list:

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;
    }

Any ideas on what I'm doing wrong?


I haven't dug into the code, yet, but have you considered using an Attribute to denote which properties are recursive? That might save you the headache of having to maintain the separate static list of properties. It seems like the list approach could be prone to potentially difficult synchrnonization issues.

ETA: Sample code:

If I'm understanding this correctly, something like this would probbaly work for a property-level attribute. It includes a helper method to retrieve the properties marked as Recursive from the given type, which might help when building the tree.

[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];
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜