Lostaunaum
Lostaunaum

Reputation: 705

Iterating Through a C# Object

I am looking for the most efficient way of iterating through attributes within an object and checking to see if it has a custom decorator. The challenge is that my object has other objects within it that may have this custom decorator and the SUB-Objects may have objects as well with decorators.

For now the code down below is only reaching into the first layer of sub objects is there a particular way in which I can go within the loop N times efficiently?

List<PropertyInfo> allProperties = type.GetProperties().ToList();

Dictionary<string, List<string>> groupIndexes = new Dictionary<string, List<string>>();

foreach (var property in type.GetProperties())
{
    var nestedProperties = property.PropertyType.GetProperties();
    foreach (var nestedProperty in nestedProperties)
    {
        var singleNestedPropertyIndex = nestedProperty.GetCustomAttribute<SingleIndexAttribute>();
        var groupNestedIndex = nestedProperty.GetCustomAttribute<GroupIndexAttribute>();
        var ttlIndex = property.GetCustomAttribute<TTLIndexAttribute>();

        if (singleNestedPropertyIndex != null || groupNestedIndex != null || ttlIndex != null)
        {
            allProperties.Add(nestedProperty);
        }
    }
}

Upvotes: 2

Views: 205

Answers (2)

Emre Kabaoglu
Emre Kabaoglu

Reputation: 13146

You can perform it by creating recursive method;

    public static void FindSpecialProperties(PropertyInfo property, List<PropertyInfo> allProperties, HashSet<PropertyInfo> recursivedProperties)
    {
        if (recursivedProperties.Contains(property))//Eliminate already recursived property
        {
            return;
        }
        recursivedProperties.Add(property);
        var properties = property.PropertyType.GetProperties();
        if (properties.Length == 0)
        {
            return;
        }
        foreach (var propertyInfo in properties)
        {
            var singleNestedPropertyIndex = propertyInfo.GetCustomAttribute<SingleIndexAttribute>();
            var groupNestedIndex = propertyInfo.GetCustomAttribute<GroupIndexAttribute>();
            var ttlIndex = property.GetCustomAttribute<TTLIndexAttribute>();

            if (singleNestedPropertyIndex != null || groupNestedIndex != null || ttlIndex != null)
            {
                allProperties.Add(propertyInfo);
            }
            allProperties.Add(propertyInfo);
            FindSpecialProperties(propertyInfo, allProperties, recursivedProperties);
        }
    }

Usage

        var recursivedProperties = new HashSet<PropertyInfo>();
        var allProperties = type.GetProperties().ToList();
        foreach (var property in type.GetProperties())
        {
            FindSpecialProperties(property, allProperties, recursivedProperties);
        }

Upvotes: 0

Erik
Erik

Reputation: 51

You could do it non-recursively by keeping a stack of properties yet-to-visit and a hash set of properties already visited. Then, you can do a while loop on the properties yet-to-visit until you've hit them all.

For example (note: code isn't tested):

HashSet<PropertyInfo> visitedProperties = new HashSet<PropertyInfo>();
Stack<PropertyInfo> remainingProperties = new Stack<PropertyInfo>(type.GetProperties());
List<PropertyInfo> foundProperties = new List<PropertyInfo>();

while (remainingProperties.Count > 0)
{
    var currentProperty = remainingProperties.Pop();

    // Process this property if we haven't visited it yet
    // Add returns true if the element is not yet in the set
    if (visitedProperties.Add(currentProperty))
    {

        // Add sub-properties to the remaining property list if we haven't visited them
        var nestedProperties = currentProperty.PropertyType.GetProperties();
        foreach (var nestedProperty in nestedProperties)
        {
            if (!visitedProperties.Contains(nestedProperty))
            {
                remainingProperties.Push(nestedProperty);
            }
        }

        // Check the current property for attributes
        var singleNestedPropertyIndex = nestedProperty.GetCustomAttribute<SingleIndexAttribute>();
        var groupNestedIndex = nestedProperty.GetCustomAttribute<GroupIndexAttribute>();
        var ttlIndex = property.GetCustomAttribute<TTLIndexAttribute>();

        if (singleNestedPropertyIndex != null || groupNestedIndex != null || ttlIndex != null)
        {
            foundProperties.Add(nestedProperty);
        }
    }
}

This will perform in O(N) time, where N is the total number of properties and nested sub-properties in the entire tree.

Upvotes: 1

Related Questions