Reputation: 705
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
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
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