Serialisation in WP7 - what am I missing?
What with tombstoning, serialisation is pretty central to WP7 apps. 开发者_如何学编程And location based apps are all the rage. But when I tried to put a GeoCoordinate into isolated storage settings, it failed to rehydrate later, and I ended up serialising lat and lng independently, which is highly unsatisfactory as I've ended up with boatloads of ad hoc serialisation code. I've cleaned it up somewhat using reflection, but really it's all a big mess.
What's the deal here? Is there a Right Way that I haven't learnt?
And if not, what were the writers of the GeoCoordinate class thinking? Annotation with the DataMember attribute is all it would have taken. Did it never cross their minds that locations might be part of app state in a WP7 app?
I've already seen this piece on serialisation and isolated storage files as well as this rather more interesting piece which links to a rather basic DIY binary serialisation helper (Microsoft's BinaryFormatter class is not available).
Mango includes Silverlight4, or so I'm told (my notebook doesn't have enough RAM, and she who must be obeyed has forbidden me to build a bigger system till after our August ski trip) - does anyone know whether this means BinaryFormatter will be available? I could reproduce BinaryFormatter but I'd rather not.
Unless I'm misunderstanding you, could you not just cast the values of your GeoCoordinate into a custom, serializable object? Rehydrating is simply deserializing your object and creating a new GeoCoordinate object.
I'm not sure if BinaryFormatter is avaialable in the Mango toolkit, but the Mango toolkit is already out (beta) so you could take a look.
Although I maintain my opinion that Microsoft should exercise some common sense and ensure that classes like GeoCoordinate are DataContract serialisable, I have found a convenient workaround. Generally when one is doing this sort of work, one has imported the interface for the BingRoute webservice, or similar.
Obviously all of the classes therein are serialisable so I converted all my code to use the BingRoute.Location
type instead of GeoCoordinate
, and the problem disappears. Where necessary, an extension method ToGeoCoordinate()
makes the conversion sufficiently unobtrusive that the intent of existing code is unobscured.
public static GeoCoordinate ToGeoCoordinate(this BingRoute.Location loc)
{
return new GeoCoordinate(loc.Latitude, loc.Longitude, loc.Altitude);
}
If you take my advice then sooner or later you will miss GeoCoordinate's GetDistanceTo() method. Extension methods are your friend here too.
You could convert both points to GeoCoordinate
and use the built-in method, but this will produce large numbers of transient objects and at some point your app will choke while the garbage collector does its duty.
I threw in the other built-in location type for good measure. Note that the distance code implements Haversine, which is a Great Circle computation with a number of limitations. Caveat emptor.
public static double GetDistanceTo(this BingRoute.Location A, BingRoute.Location B)
{
return GetDistanceTo(A.Latitude, A.Longitude, B.Latitude, B.Longitude);
}
public static double GetDistanceTo(
this Microsoft.Phone.Controls.Maps.Platform.Location A,
Microsoft.Phone.Controls.Maps.Platform.Location B)
{
return GetDistanceTo(A.Latitude, A.Longitude, B.Latitude, B.Longitude);
}
static double toRad = Math.PI / 180D;
static double toDeg = 180D / Math.PI;
static double GetDistanceTo(double lat1, double lng1, double lat2, double lng2)
{
lat1 *= toRad;
lng1 *= toRad;
lat2 *= toRad;
lng2 *= toRad;
double sin_dLng_on2_squared = Math.Sin((lng2 - lng1) / 2);
sin_dLng_on2_squared *= sin_dLng_on2_squared;
double sin_dLat_on2_squared = Math.Sin((lat2 - lat1) / 2);
sin_dLat_on2_squared *= sin_dLat_on2_squared;
double a = sin_dLat_on2_squared + Math.Cos(lat1 * Math.Cos(lat2) * sin_dLng_on2_squared);
double c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
return c * 6371000;
}
It's also quite important to note that the more you store, the slower your app starts because it takes longer to create the settings object on activation. So you're best advised to store only simple option state here and keep as much as possible in isolated storage files.
精彩评论