09 November 2013

Build for both-Reflection bits & pieces for Windows Phone 8 and Windows 8

This is a bit of an odd post – it’s the things I learned while porting SilverlightSerializer 2 from Windows Phone to Windows 8 Store apps code. For those who don’t know what that is – it’s a very fast serializer, created by the brilliant Mike Talbot that’s able to store complex objects graphs in a very compact binary format. I use it to store an app’s state by simply serializing the view model graph to storage. For my (now) only Windows Store app I made a half-*ssed attempt to convert the much simpler SilverlightSerializer  v1 last year – but that’s slower and much less capable – especially my port. I was very much in a hurry then, so I cut out everything I did not need.

Anyway – SilverlightSerializer is a big chunk of reflection code. To get it to work in Windows Store apps, I had to change quite a lot of things – but then again a lot less than I thought. Even more shocking was the fact it worked without any problems when I linked the adapted code back to my Windows Phone project. That’s the power of the common Windows Runtime – no #if WINDOWS_PHONE preprocessor statements here!

So anyway, here’s what I learned. I wrote it in a kind of boring old-new style, but I found very little on this subject on the web, so I hope this is useful for people digging into reflection on Windows Store apps and hitting the wall when trying to do it ‘the new way’.

Properties and Fields

Get an object’s properties:

  • Old code: Type.GetProperties()
  • New code: Type.GetRuntimeProperties()

Get a single property:

  • Old code: Type.GetProperty("MyProperty")
  • New code: Type.GetRuntimeProperty("MyProperty")

Get a property’s get method

  • Old code: PropertyInfo.GetGetMethod();
  • New code: PropertyInfo.GetMethod;

Get a property’s set method

  • Old code: PropertyInfo.GetSetMethod();
  • New code: PropertyInfo.SetMethod;

Get public non-static properties that can be get and set

  • Old code:Type.GetProperties(BindingFlags.Instance | BindingFlags.Public).
                          Where(p => p.GetSetMethod() != null));
  • New code:Type.GetRuntimeProperties().
                             Where(p=> p.GetMethod != null && p.SetMethod != null &&
                                         !p.SetMethod.IsStatic && !p.GetMethod.IsStatic &&
                                         p.GetMethod.IsPublic && p.SetMethod.IsPublic);

Get an object’s Fields:

  • Old code: Type.GetFields()
  • New code: Type.GetRuntimeFields()

Get a single Field:

  • Old code: Type.GetField("MyProperty")
  • New code: Type.GetRuntimeField("MyProperty")

You can already see two patterns here – in stead of GetXYZ you do GetRuntimeXYZ. This “Runtime” indicates all an objects has available on runtime – that is, both it’s own properties, methods etc. and those of it’s parents. The other pattern is that in the Windows Runtime there is a tendency to use properties in stead of zero-parameter get methods.

Attributes

Determine whether a property has a custom attribute or not

  • Old code: PropertyInfo.GetCustomAttributes(typeof(DoNotSerialize), true).Any()
  • New code: PropertyInfo.GetCustomAttribute<DoNotSerialize>(true) != null

Type info

Determine if a type is an enum

  • Old code: Type.IsEnum
  • New code: Type.GetTypeInfo().IsEnum

Determine if a type is a generic type

  • Old code: Type.IsGenericType
  • New code: Type.GetTypeInfo().IsGenericType

Determine a type’s generic arguments

  • Old code: Type.GetGenericArguments()
  • New code: Type.GetTypeInfo().GenericTypeArguments

Find a type’s default constructor

  • Old code:Type.GetConstructor(new Type[] { });
  • New code: Type.GetTypeInfo().DeclaredConstructors.
                            FirstOrDefault(p => !p.GetParameters().Any());

Determine if a type implements an interface

  • Old code: Type.GetInterface("IEnumerable", true) != null;
  • New code: GetTypeInfo().ImplementedInterfaces.FirstOrDefault(
                         p => string.Compare(p.Name, name, ignoreCase?
                         StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)==0);

I must admit being a bit lazy on this one – this was used quite a number of times in SilverlightSerializer, so I made the following extension method

using System;
using System.Linq;
using System.Reflection;

namespace WpWinNl.Utilities
{
  public static class TypeExtensions
  {
    public static Type GetInterface(this Type type, string name, bool ignoreCase)
    {
      return type.GetTypeInfo().ImplementedInterfaces.FirstOrDefault(
        p => string.Compare(p.Name, name, ignoreCase? 
            StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)==0) ;
    }
  }
}

and was done with it ;-). Beware – this is not something I recommend – making the new API compatible with the old. Rather, make it the other way around. But for porting existing code – especially code you did not write yourself – this can be a helpful way to save time.

Miscellaneous

Creating delegates

  • Old code: Delegate.CreateDelegate(typeof(DelegateType), MethodInfo);
  • New code: MethodInfo.CreateDelegate(typeof(DelegateType));

A MethodInfo is something you would get out of for instance PropertyInfo.GetMethod. I must admit to code in SilverlightSerializer is quite complex at this point, and I don’t understand the whole detail. But this seems to work, and I suggest people more interested in the details to have a look at the code. I will post the whole shebang soon.

Sorry, no sample this time ;-)

07 November 2013

Build for both-Converters for Windows Phone 8 and Windows 8.1 Store apps

Our Dutch DPE Rajen Kishna has been quite heavily banging the ‘build for both’ drum for some time now, and after having spent quite some time on exclusive Windows Phone development I decided to see if I could rewrite the code for my wp7nl library on codeplex so that it would easily work for Windows Phone 8 and Windows 8.1 store apps – of course in order to be able to port my apps for Windows 8.1 as well.

At the moment of this writing I am still very much in the process of converting and rewriting code, but here is already the first part one of my yet-to-be-decided-number-of-parts of a build-for-both series – about how to write a ValueConverter that runs on both platforms. Since this handles about UI stuff, I could not go PCL, so I chose the shared code route.

ValueConverters need to implement IValueConverter, a simple two-method interface. In Windows Phone (and Silverlight and WPF) this interface is

Convert(object value, Type targetType, object parameter, CultureInfo culture);
ConvertBack(object value, Type targetType, object parameter, 
CultureInfo culture);
So far so good, but for some reason I not have fathomed yet Microsoft have decided to change the IValueconverter signature to
Convert(object value, Type targetType, object parameter, string culture);
ConvertBack(object value, Type targetType, object parameter, string culture);

This is something you can moan about, or something you can solve. I choose the latter part. First of all, I implemented an abstract  base class BaseValueConverter

using System;
using System.Globalization;
#if WINDOWS_PHONE
using System.Windows.Data;
#else
using Windows.UI.Xaml.Data;
#endif

namespace WpWinNl.Converters
{
  public abstract class BaseValueConverter : IValueConverter
  {
    public abstract object Convert(object value, Type targetType, 
object parameter, CultureInfo culture); public abstract object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture); public object Convert(object value, Type targetType, object parameter,
string language) { return Convert(value, targetType, parameter, new CultureInfo(language)); }
public object ConvertBack(object value, Type targetType, object parameter,
string language) { return ConvertBack(value, targetType, parameter,
new CultureInfo(language)); } } }

Important to know is that the IValueConverter interface is defined in namespace System.Windows.Data in Windows Phone, and in Windows.UI.Xaml.Data in Windows Store apps. Fortunately, every Windows Phone project automatically defines the WINDOWS_PHONE conditional compilation symbol, so we can put these #if-#else-#endif preprocessor directives in code.

Then I took this little converter, that translates bound text to uppercase (written by my felllow MVP Timmy Kokke and added to wp7nl by him some months ago), and rewrote it using BaseValueConverter:

using System;
using System.Globalization;
using System.Windows;
#if !WINDOWS_PHONE
using Windows.UI.Xaml;
#endif

namespace WpWinNl.Converters
{
  /// <summary>
  /// Converts a string to all uppercase letters
  /// </summary>
  public class ToUpperValueConverter : BaseValueConverter
  {
    public override object Convert(object value, Type targetType, 
                           object parameter, CultureInfo culture)
    {
      if (value == null) return string.Empty;

      return value.ToString().ToUpperInvariant();
    }

    public override object ConvertBack(object value, Type targetType, 
                                       object parameter, CultureInfo culture)
    {
      return DependencyProperty.UnsetValue;
    }
  }
}

And that is all. So how does this work? In Windows Store apps, the methods with the string language parameters are called, but these make a CultureInfo from the string, and then call the methods using a CultureInfo. In Windows Phone, the CultureInfo using methods are directly called, and the string language parameters are simply not used. I could have put these between preprocessor directives as well, but I am not very fond of too much directives in the code itself.

I have included a sample Windows Phone and Windows Store app, that both show a button with the text HELLO in capitals, using this converter. The shared source code comes from a separate directory and is added as link to both solutions. When my library is finished you will of course simply make a reference to the right library, but in the mean time you know how you can write cross platform converters yourself.

Update: irony has it that Rajen itself, in the article I link to, refers to his October starter template which incorporates a BaseConverter class. His approach is a little bit different from mine, but the general idea - using shared code for a base class - is the same. As I apparently downloaded the wrong zip file from his SkyDrive, I did not see it before I wrote this. I don't know if this is prior art, but I like to be thorough in this. Great minds apparently think alike, and I sure was inspired by his (older) template to use shared code.