Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.Reflection in a Windows Mobile Project

Before I start, Let me clear up any confusion before anyone suggests or asks the question..

This Question is related to "Windows Mobile 6 Professional", NOT Windows Phone 7 and it can't be ported to windows phone 7 as it has to go on to an older device.

Now, with that out of the way...

I'm currently trying to port a C# library that I have the source for to run on a windows mobile 6 device, Iv'e coded these things it seems like for ever, but there's one thing Iv'e never had to deal with until now and that's reflection.

Now everyone know that the .NET compact framework does have some limitations, and it appears that lack of support for a lot of the methods and properties in the 'System.Reflection' namespace is one of them.

The actual desktop version of the library is set to target .NET V2.0, and I have devices that are running .NET 3.5 SP1 so for the most part Iv'e had very little problem in getting things to work, a cannot however seem to find a sensible to get the following 2 chunks of code working:

        var a = AppDomain.CurrentDomain**.GetAssemblies**();
        foreach (var assembly in a)
        {
            if (assembly is System.Reflection**.Emit.**AssemblyBuilder) continue;
            if (assembly**.GetType().**FullName == "System.Reflection.Emit.InternalAssemblyBuilder") continue;
            if (assembly**.GlobalAssemblyCache** && assembly**.CodeBase** == Assembly.GetExecutingAssembly()**.CodeBase**) continue;

            foreach (var t in GetLoadableTypes(assembly))
            {
                if (t.IsInterface) continue;
                if (t.IsAbstract) continue;
                if (t.IsNotPublic) continue;
                if (!typeof(IGeometryServices).IsAssignableFrom(t)) continue;

                var constuctors = t.GetConstructors();
                foreach (var constructorInfo in constuctors)
                {
                    if (constructorInfo.IsPublic && constructorInfo.GetParameters().Length == 0)
                        return (IGeometryServices)Activator.CreateInstance(t);
                }
            }
        }

And

        catch (**ReflectionTypeLoadException** ex)
        {
            var types = ex**.Types**;
            IList<Type> list = new List<Type>(types**.Length**);
            foreach (var t in types)
                if (t != null && t**.IsPublic**)
                    list.Add(t);
            return list;
        }

Specifically, those items in bold in the above code are the methods and properties that don't appear to be present in the compact framework, and after spending quite a chunk of time with intellisense and the object browser, Iv'e not found anything that returns (or makes available) the same types.

My question then is as follows:

Does anyone have any experience of using reflection in the Compact .NET framework, and can suggest how this code can be made to work as expected, or am I going to have to start writing custom stubs and functionality to replace the missing methods.

I know there is some reflection capabilities on the framework, so I'm sure there must be an equivalent way of achieving it.

Just on a final note, for anyone who may recognise the code. YES it is from the .NET topology suite, and yes it is that library I'm trying to build a WM6 version of, so if you know of anyone that has already done it please do put a comment on to that effect, and I'll go take a look at the easier path :-)

======================================================================

Update after posting

It appears 'Bold' text doesn't work in code snippets, so those methods / properties in the above code that are surrounded by ** are the parts supposed to be in bold.

like image 712
shawty Avatar asked Apr 21 '26 22:04

shawty


1 Answers

So after studying some older builds and an experimental Silverlight build (Which apparently has a lot of the same limitations as Windows Mobile / CE)

I figured out how to make the magic work.

The first part was to fill the array with 'Assembly' structures representing the assemblies to search. Originally it was:

var a = AppDomain.CurrentDomain.GetAssemblies(); 

but since GetAssemblies doesn't exist in WM then the quickest way is to use the following:

var a = new[] {Assembly.GetCallingAssembly(), Assembly.GetExecutingAssembly()}; 

Now in my case this meant that I got two identical assemblies, but if I was calling an Assembly from my main exe which in turn used GeoAPI then 2 different assemblies would be shown here.

The next challenge was the "stripping out" of assemblies we didn't need to check:

if (assembly is System.Reflection.Emit.AssemblyBuilder) continue; 

if (assembly.GetType().FullName == System.Reflection.Emit.InternalAssemblyBuilder") continue; 

if (assembly.GlobalAssemblyCache && assembly.CodeBase == Assembly.GetExecutingAssembly().CodeBase) continue; 

The first and second instances never crop up in WM6 so it's safe to just comment them out. The second one does work, but since you'll never see any assemblies with the given check name (Due to it being missing) on WM6 then again, you should be safe to comment it out. I didn't comment it out, but it also never got triggered as true.

The final part (at least as far as the original puzzle went anyway) was this:

foreach (var t in GetLoadableTypes(assembly)) 
{ 
  if (t.IsInterface) continue; 
  if (t.IsAbstract) continue; 
  if (t.IsNotPublic) continue; 
  if (!typeof(IGeometryServices).IsAssignableFrom(t)) continue; 

In my original attempt 'isInterface' & 'isNotPublic' where missing, however once I managed to fix up the contents of the 'var a' variable above with the data type it expected, everything started to work ok with nothing missing.

The final question is? Did this solve everything? Well not quite....

It turns out that the whole purpose of the 'ReflectInstance' method in GeoAPI was to find a user defined 'GeometryFactory' using an 'IGeometryServices' interface.

Since I was only reflecting over the assembly I was calling from (var a above) then the 'NetTopologySuite' (Where the geometry factory is defined) was not added to the select list (Obviously CurrentDomain.GetAssemblies includes this)

The net result was I still ended up hitting the exception at the end as no Assemblies of the correct type could be located.

It turns out however, that in the 'Geometry' constructor in GeoAPI has an overload that allows you to pass in a GeometryFactory, when you do this it completely ignores the ReflectInstance method and just uses what it's told.

or to put it another way , I never had to do any of this in the first place, I could have just set the method to return 'null' and passed in the geometry factory I wanted to use.

Anyway, if anyone is interested I now have a working copy of:

GeoAPI.NET NetTopologySuite Wintellect.PowerCollections

Built and working fine under Windows Mobile 6 and Windows CE with .NET CF 3.5.

like image 88
shawty Avatar answered Apr 24 '26 15:04

shawty



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!