I've been doing some app-building with Silverlight lately and exploring the limitations of the platform in comparison to the full desktop CLR and what that means for the Silverlight "ecosystem". Those limitations can be summed up with 3 items:
I think #3 will begin to become a non-issue as more component providers provide builds for Silverlight. #2 can be broken down into 2 areas:
The second is where my interest lies, and intersects with #1 (the new security model). We've done extensive threat modeling against our APIs as well as automated tooling that has either removed (or made internal) certain APIs, or marked them as SecurityCritical, meaning they cannot be called directly from "user" code.
In addition, the security model requires safe, verifiable user code. Normally when developing on the desktop CLR, unless you are specifically targeting a low trust environment, you can do whatever you like.
So, for this exercise, I pulled out my trusty STDF parser (blogged here and here). I've used this project as a test vehicle for both v2.0 and Orcas, and it's served well as a project that leverages a large cross-section of features in the Framework, from high-level stuff like Linq down to expression tree inspection and further down to LCG/RefEmit.
In short, I was able to get the parser working without too much trouble. I felt like creating a source bed that intended to target both Silverlight and the Desktop should be an attainable goal. You just have to switch your mindset from binary compatibility to source compatibility.
I combated the reduced surface area with extension methods, which worked quite well to centralize the "overload shims" that needed to be "Silverlight-only", as well as for a general refactoring tool. My goal is to have all the desktop vs. Silverlight differences centralized into files that are either included or excluded from the build depending on which platform I'm targeting. I wish you could create extension properties. That would let me close all the surface area discrepancies that aren't caused by missing/irrelevant technology areas.
I was pleased that 99% of my LCG codegen stuff "just worked". I make heavy use of Reflection.Emit via DynamicMethod to generate my record parsers based on attributes on the record classes. The 2 problems I ran into were:
This brings me to constrained callvirt, an interesting little IL tidbit I discovered in the porting process. Calling conventions are subtly different between reference types and value types, and it also depends on whether the given method is actually overridden in the value type (which can lead to confusing breaks when that state changes). In the v1.x days, you always knew the type you were dealing with, so it didn't matter that much and you could generally always create the right sequence of IL to make a call. V2.0 introduced generics, which meant that you couldn't emit unified IL for both the possibility of reference types or value types. This meant there needed to be a way to unify the IL for the 2 cases. This is where the constrained prefix came in. It allows you to write unified IL that works regardless of whether you're working with a value type or a reference type (think generics constrained by an interface, or calling a method defined on System.Object like ToString()).
Anyway, I was able to fix my unverifiable code by utilizing the constrained prefix. It also simplified my codegen logic significantly in a number of places where I had different paths based on whether I was working with a value type or not.
All in all, I was pleased with the results. I'll be posting a sample Silverlight app using the library when I get some UI stuff figured out.
Remember Me
Page rendered at Thursday, August 21, 2008 7:07:29 PM (Pacific Standard Time, UTC-08:00)
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.