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

Reflection and methods using params

by Geert 24. September 2011 15:20

Recently, I had to get a method with the following signature using reflection:

   1: public static object Get(this IContainer container, Type type, params IParameter[] parameters)

So, I was wondering how to get the right method overload with the params parameter. While googling it, the only stuff I could find was on how to find a method with parameters, even when searching for params (damn you sites for copying forum posts, I don’t want the same result several times…).

After using type.GetMethods(), I took a good look at the method info, and it seemed that the params IParameter[] was there as IParameter[].

After thinking a bit about thi I called myself stupid, continued working. After a tip of Joost van Schaik, I decided to blog about this so hopefully if you are looking for this, you don’t have to look any further.

Wrap up

If you need a method with the params, just use this code:

   1: type.GetMethod(“Get”, new Type[] { typeof(IContainer), typeof(Type), typeof(IParameter[]) });

Tags:

C#

Getting a private field of a base class using reflection

by Geert 10. September 2010 16:05

Today, I needed a way to get a private field from a type (just for reading only, but since the designer of the class has no functionality to retrieve it). Anyway, I though to be smart by using this code:

 

FieldInfo myPrivateField = myType.GetField(“myPrivateFieldName”, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

 

Unfortunately, Microsoft “wisely” decided not to allow BindingFlags.FlattenHierarchy to be used on non-public fields declared in base classes. Because of this “wise” decision, I had to write the functionality myself, and lost another hour of valuable time. To spare you this time, here is the method. It recursively checks the base class for the private field:

 

/// 
/// Gets the field info for a specific field. But, the good thing about this is that it also supports
///  for private members in base classes.
/// 
/// The type.
/// Name of the field.
/// The binding flags.
///  or null if the field is not found.
public static FieldInfo GetFieldAndAllowPrivateBaseMembers(this Type type, string fieldName, BindingFlags bindingFlags)
{
	// Declare variables
	FieldInfo fieldInfo = null;
	bool flattenHierarchy = Enum.Flags.IsFlagSet(bindingFlags, BindingFlags.FlattenHierarchy);

	// Clear flatten hierarchy flag if included
	if (flattenHierarchy)
	{
		bindingFlags = Enum.Flags.ClearFlag(bindingFlags, BindingFlags.FlattenHierarchy);
	}

	// Search as long as there is a type
	while (type != null)
	{
		// Use reflection
		fieldInfo = type.GetField(fieldName, bindingFlags);

		// Should we flatten the hierarchy?)
		if (flattenHierarchy)
		{
			// Yes, do we have a field?
			if (fieldInfo != null) break;

			// Get base class
			type = type.BaseType;
		}
		else
		{
			// Break
			break;
		}
	}

	// Return result
	return fieldInfo;
}

 

Of course, I will also include this in Catel.

kick it on DotNetKicks.com

Method to get private fields of base classes

Tags:

C# Development


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!