Click here to Skip to main content
13,549,148 members
Click here to Skip to main content
Add your own
alternative version

Tagged as


Posted 3 Oct 2012
Licenced CPOL

Reflection & Order of Discovered Properties

, 3 Oct 2012
Rate this:
Please Sign up or sign in to vote.
Reflection & Order of Discovered Properties

In the .NET environment, Reflection provides several methods to obtain information about any type from the type system. One of these methods is GetProperties method which retrieves a list of all the properties of a given type. This method returns an array of PropertyInfo objects.

PropertyInfo[] propListInfo = type.GetProperties();

In most cases, you don't care, but the order of the properties does not have to be the same if you run this method several times. This is well described in the documentation of this method. Microsoft also states that your code should not be depending on the order of the properties obtained.

I had a very nice example of a bug resulting from the misuse of this method. An ObjectComparer class, which is dedicated to the comparison of two objects of the same type by recursively comparing its properties, which I have inherited as legacy code on my current Silverlight project.

I have noticed that the results of the comparison are not the same everytime I run the comparison. Concretely, the first time the comparison was run on two same objects, it always told me that the objects are not equal. Take a look at the problematic code, which I have simplified a bit for this post:

private static bool CompareObjects(object initialObj, object currentObj, IList<String> filter)
 string returnMessage = string.Empty;

 Type type = initialObj.GetType();
 Type type2 = currentObj.GetType();

 PropertyInfo[] propListInfo = type.GetProperties(BindingFlags.GetProperty | 
 BindingFlags.Public | BindingFlags.Instance).Where(x => !filter.Contains(x.Name)).ToArray();
 PropertyInfo[] propListInfo1 = type2.GetProperties(BindingFlags.GetProperty | 
 BindingFlags.Public | BindingFlags.Instance).Where(x => !filter.Contains(x.Name)).ToArray();

 //if class type is native i.e. string, int, boolean, etc.
 if (type.IsSealed == true && type.IsGenericType == false)
  if (!initialObj.Equals(currentObj))
   return false;
 else //class type is object
  //loop through each property of object
  for (int count = 0; count < propListInfo.Length; count++){
   var result = CompareValues(propListInfo[count].GetValue(initialObj),
   if(result == false) {
    return result;
 return true;

So in order to correct this code, you will have to order both arrays by MetadataToken, which is a unique identifier of each property.

propListInfo = propListInfo.OrderBy(x=>x.MetadataToken).ToArray();
propListInfo1 = propListInfo1.OrderBy(x=>x.MetadataToken).ToArray();

There is some more information about how reflection works in this blog post. The issue is that the Reflection engine holds a "cache" for each type, in which it stocks the already "discovered" properties. The problem is that, this cache is cleared during garbage collection. When we ask for the properties, then they are served from the cache in the order in which they have been discovered.

However in my case, this information does not help. The issue occurs only the first time that I ask the ObjectComparator to compare the objects and there is no reason that there should be any garbage collection between the first and second run... well no idea here. Sorting by MetadataToken has fixed the issue for me.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Junior) OCTO Technology
Czech Republic Czech Republic
Writing software at ITG RFQ-hub.
Articles at OCTO blog

You may also be interested in...

Comments and Discussions

SuggestionI know it wasn't the point, but this could be more efficient Pin
Matt T Heffron3-Oct-12 13:41
memberMatt T Heffron3-Oct-12 13:41 
As shown, this code is doing a fair amount of unnecessary work. If you're going to show something, it might as well be efficient. Smile | :)
The reflection to get the two PropertyInfo[] is done before checking if it is necessary. It should be moved into the else branch.
The Filtering by property name is inefficient. A HashSet<string> could speed it up in the general case.
If this is likely to be called frequently on objects from the same set of types, then caching the PropertyInfo collections by type can save the Reflection overhead (at the cost of some memory).
How does this look?
public static class ReflectiveObjectComparer
  private static Dictionary<Type, IEnumerable<PropertyInfo>> PropertySets = new Dictionary<Type, IEnumerable<PropertyInfo>>();
  private static Func<PropertyInfo, int> OrderKeyFunction = x => x.MetadataToken;

  private static bool CompareObjects(object initialObj, object currentObj, IList<String> filter)
    const BindingFlags propertyFlags = BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance;
    Type initialType = initialObj.GetType();
    Type currentType = currentObj.GetType();

    //if class type is native i.e. string, int, boolean, etc.
    if (initialType.IsSealed && !initialType.IsGenericType)
      return initialObj.Equals(currentObj);
    //class type is object
    IEnumerable<PropertyInfo> initialProperties;
    if (!PropertySets.TryGetValue(initialType, out initialProperties))
      initialProperties = initialType.GetProperties(propertyFlags).OrderBy(OrderKeyFunction);
      PropertySets[initialType] = initialProperties;

    IEnumerable<PropertyInfo> currentProperties;
    if (!PropertySets.TryGetValue(currentType, out currentProperties))
      currentProperties = currentType.GetProperties(propertyFlags).OrderBy(OrderKeyFunction);
      PropertySets[currentType] = currentProperties;

    HashSet<string> filterNames = new HashSet<string>(filter ?? Enumerable.Empty<string>());

    // Avoid constructing additional arrays of PropertyInfo
    Func<PropertyInfo, bool> filterFunction = pi => filterNames.Contains(pi.Name);
    var filteredIP = initialProperties.Where(filterFunction);
    var filteredCP = currentProperties.Where(filterFunction);
    var propertyPairs = filteredIP.Zip(filteredCP, (ipi, cpi) => new { InitialPI = ipi, CurrentPI = cpi });
    //loop through each property of objects
    foreach (var pp in propertyPairs)
      var result = CompareValues(pp.InitialPI.GetValue(initialObj, null), 
                                 pp.CurrentPI.GetValue(currentObj, null));
      if (!result)
        return false;
    return true;

The .Zip() extension method is in .NET 4, but I think you could fake it using .Join().
GeneralRe: I know it wasn't the point, but this could be more efficient Pin
Jan Fajfr4-Oct-12 10:45
memberJan Fajfr4-Oct-12 10:45 
GeneralRe: I know it wasn't the point, but this could be more efficient Pin
Matt T Heffron4-Oct-12 11:24
memberMatt T Heffron4-Oct-12 11:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.180515.1 | Last Updated 3 Oct 2012
Article Copyright 2012 by hoonzis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid