FlattenHierarchy for static members in WinRT

by Geert 2. July 2012 21:11

Recentely, I needed the same behavior of BindingFlags.FlattenHierarchy in WinRT that we are used to in .NET. At first, this didn’t work out because I was using the consumer preview, not the release preview.

In the release preview, Microsoft added great extensions methods as the RuntimeReflectionExtensions class. However, I was still facing issues where static base members were not returned by the extension methods. Below is an example of a unit test that will fail:

   1:  public class Foo 
   2:  { 
   3:      public static int StaticFooField; 
   4:  }
   5:   
   6:  public class Bar : Foo 
   7:  { 
   8:      public static int StaticBarField; 
   9:  }
  10:   
  11:  [TestClass]
  12:  public class ReflectionFacts
  13:  {
  14:      [TestMethod]
  15:      public void ReturnsAllStaticInheritedMembers()
  16:      {
  17:          var allItems = typeof(Bar).GetRuntimeFields().ToList();
  18:   
  19:          Assert.AreEqual(2, allItems.Count);
  20:      }
  21:  }

Where I would expect both fields to be returned, the GetRuntimeFields() method will only return all inherited non-static members. It does flatten the hierarchy for all non-static members though. However, I needed to achieve the same behavior as FlattenHierarchy | Static in my code.

I wrote lots of extension methods to achieve the same reflection code in both WinRT and .NET. Below shows how to walk down the stack to get the same behavior as FlattenHierarchy | Static:

   1:  /// <summary>
   2:  /// Gets the fields.
   3:  /// </summary>
   4:  /// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
   5:  /// <param name="bindingFlags">The binding flags.</param>
   6:  /// <returns>An array of <see cref="FieldInfo"/>.</returns>
   7:  /// <exception cref="ArgumentNullException">The <paramref name="typeInfo"/> is <c>null</c>.</exception>
   8:  public static FieldInfo[] GetFields(this TypeInfo typeInfo, BindingFlags bindingFlags)
   9:  {
  10:      Argument.IsNotNull("typeInfo", typeInfo);
  11:   
  12:      var flattenHierarchy = ShouldFlattenHierarchy(bindingFlags);
  13:      var source = flattenHierarchy ? typeInfo.AsType().GetRuntimeFields().ToList() : typeInfo.DeclaredFields.ToList();
  14:   
  15:      var includeStatics = Enum<BindingFlags>.Flags.IsFlagSet(bindingFlags, BindingFlags.Static);
  16:   
  17:      // TODO: This is a fix because static members are not included in FlattenHierarcy, remove when this is fixed in WinRT
  18:      if (flattenHierarchy)
  19:      {
  20:          var baseType = typeInfo.BaseType;
  21:          if ((baseType != null) && (baseType != typeof(object)))
  22:          {
  23:              source.AddRange(from member in GetFields(baseType.GetTypeInfo(), bindingFlags)
  24:                              where member.IsStatic
  25:                              select member);
  26:          }
  27:      }
  28:   
  29:      if (!includeStatics)
  30:      {
  31:          source = (from x in source
  32:                      where !x.IsStatic
  33:                      select x).ToList();
  34:      }
  35:   
  36:      return (from x in source
  37:              where x.IsStatic == includeStatics
  38:              select x).ToArray();
  39:  }

If you are interested in more reflection extensions, see this file.

WinRT is quite cool when you get it all working out Smile

Tags: , ,

Catel | WinRT

Comments are closed

About the Author

Geert van Horrik is an independent freelance software developer since January 1st, 2007. Since then he was been working on several projects from C++ to C# (WPF, Silverlight, ASP.NET, etc). Currently he loves to write his software using WPF (or Silverlight if WPF isn't an option).

Lately, Geert is spending a lot of time on Catel, a free open-source MVVM Framework for WPF and Silverlight. Actually, it's more than "just" an MVVM Framework, it's a complete application library!