Silverlight 4 RC Dynamic Keyword Behavior Regressions

I have been looking around and can’t find any Release Notes or Known Issues for the SL4 RC release that came out at MIX10 a couple days ago, but our SL4 project was heavily using the dynamic keyword for Excel interop and upon testing out the new bits with it we noticed it didn’t work anymore. What I have been able to find out so far is there seem to be several new restrictions with the usage of the dynamic references.

First of all, you can no longer pass the result of a dynamic accessor to a method with the Conditional attribute. I used to be able to happily pass a dynamic property accessor result as the argument of Debug.WriteLine, which was very useful in debugging since the Immediate window in Visual Studio still doesn’t support the syntax. Now when you attempt this you will get an exception like this:


Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled by user code
  Message=Cannot dynamically invoke method 'WriteLine' because it has a Conditional attribute
  StackTrace:
       at CallSite.Target(Closure , CallSite , Type , Object )
       at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
       at NoDynamicIteration.MainPage.Button_Click(Object sender, RoutedEventArgs e)
       at System.Windows.Controls.Primitives.ButtonBase.OnClick()
       at System.Windows.Controls.Button.OnClick()
       at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
       at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)

There is a simple workaround: Assign the value to a local variables first. But, it still seems unnecessary and annoying.

Then there is a problem that affects us a bit more painfully. As anyone who has tried using this feature knows, since everthing is dynamic you get no Intellisense. We were intending to release a solution to this that was working great on this project. Basically using a code generator based on Common Compiler Infrastructure (CCI) we were able to turn COM Primary Interop Assemblies (PIA) into wrapper classes that gave strongly typed access to all of the methods, properties, events and collections of COM objects. Suddenly being a business developer who has to interact with Office applications didn’t make us second class and throw us back 10 years into a land eerily reminiscent of VBScripting.

One big challenge of that effort was figuring out how to deal with property indexers, which don’t natively exist in .NET, and collection enumerators, since collections are represented in multiple and not always consistent ways in the COM world. We did come up with a solution that used a set of Generic classes to allow flexible access to indexed property values and collection members. However, with the SL4 RC you can no longer assign the result of a dynamic accessor to a Generic-typed variable or return a value from a Generic-return-typed property or method. When you try you get:


System.NullReferenceException was unhandled by user code
  Message=Object reference not set to an instance of an object.
  StackTrace:
       at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr)
       at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL pExpr)
       at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR pExpr)
       at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
       at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable`1 listOfParameters)
       at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateExpressionTreeFromResult(IEnumerable`1 parameters, ArgumentObject[] arguments, Scope pScope, EXPR pResult)
       at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
       at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
       at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
       at Microsoft.CSharp.RuntimeBinder.CSharpConvertBinder.FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
       at System.Dynamic.DynamicMetaObject.BindConvert(ConvertBinder binder)
       at System.Dynamic.ConvertBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
       at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
       at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
       at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
       at NoDynamicIteration.MainPage.<GetWorksheets>d__6`1.MoveNext()
       at NoDynamicIteration.MainPage.Button_Click(Object sender, RoutedEventArgs e)
       at System.Windows.Controls.Primitives.ButtonBase.OnClick()
       at System.Windows.Controls.Button.OnClick()
       at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
       at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)

Not only is this extremely disappointing, but if this is not a bug it seems quite amateur. I mean really, who ships production code that throws NullReferenceExceptions? And how would I know, without spending an hour narrowing down the potential problem (which I did), that that exception was being caused because of an attempted Generic cast?

Once again, there does appear to be a workaround: Assign the dynamic result to an object, then cast to a Generic type. In my case the Generic type IS object. Can the compiler and binder seriously not figure out what is going on here?

Maybe what is most concerning about all of this is why there was such a disruptive change to an important feature between the post-Beta 2 EAP bits and the RC released less than 2 months later? I am beginning to feel like Microsoft is returning to the days when you should wait for the first service pack before you install anything. Possibly the changes were to help address the ridiculous code bloat problems the Beta 2 release had. If you peeked under the covers it appeared every line of code that used a dynamic reference caused a static object instance to be generated by the compiler. The compiled assemblies using dynamic references do appear to be quite a bit smaller with the RC, but I haven’t peeked under the hood yet to see why. I am really not convinced though that this approach and design were appropriate when I am sure there must have been alternatives that could have been designed in such a way that they were strongly typed and would have avoided much of this. And, we would have had Intellisense.

As for us, we have to ship soon, so it is looking like a possibility we will have to scrap a big component of the effort and use glorified VBScript for all of the sections that interact with COM objects, taking a way a big part of the value proposition which was to provide a better and more productive environment for that type of business development. We can’t waste a bunch of time on any more surprises from these new, unexpected and undocumented (?) limitations.

This entry was posted in Uncategorized. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Posted May 5, 2010 at 10:45 pm | Permalink

    Hey Chris, just curious – is this still a problem with SL 4 RTM?

    -Charles

  2. Posted May 9, 2010 at 8:55 pm | Permalink

    Unfortunately, from what I understand some of this is now by design and the rest was not fixed.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>