dynamic interfaces and "expando" types

Posted Sun, Apr 1 2007 15:40 by bill
A frustrating limitation of LINQ and anonymous types is that the type has to be resolved at compile time.  So "Reporting" style of queries where you can dynamically add and remove columns isn't really catered for…….
However, let's say you had a type which fro want of a better name, I'll call Expando.  This type stores properties in a dictionary, that is each property name is the dictionary key to the value.  The problem with this is it would be missing type information, so although you'd have the runtime dynamic nature, any design time code would be dealing with type Object and continually require field(Of t) calls or CType operations etc to gain strong typing.
Now consider we add to this the ability to have dynamic interfaces as what was once on the cards for VB9.  A dynamic interface would mean the type has those methods/properties, but doesn't actually need to implement an actual interface… a runtime matching that gives design time strong typing.  We'd be close, but our Expando type only has a dictionary Item property for all the properties.
But Item is also marked as Default.  So really all we'd need on is a way to tell the compiler that the dynamic interface property needs to use the Default dictionary Item, e.g.
Dynamic Interface Person
    <DictionaryItem>Property Name As String
    <DictionaryItem>Property DOB as Date
End Dynamic Itnerface
This would allow you to cast an Expando instance to a Person interface, e.g:
Instead of:
      If CType(myExpando("DOB"), Date) > Today.Addyears(-18) Then
          MsgBox CType(myExpando("Name"), String)  & " is under 18"
          MsgBox CType(myExpando("Name"), String)  & " is over 18"
      End If
you could cast to Person early on and use a Person interface, e.g:
      Dim p as Person = CType(myExpando, Person)
      If p.DOB > Today.Addyears(-18) Then
          MsgBox p.Name  & " is under 18"
          MsgBox p.Name  & " is over 18"
      End If
And you'd get the intellisense experience.
The nice thing about dynamic interfaces and a dictionary expando type is that the type could contain many other key value pairs (properties), but that won't impact on the usage as long as it has the ones you are interested in.
This brings us to the difficult part of such as a design.. what to do when things go wrong ?  I think it would be nice if you could tweak it to either throw an exception when a key doesn't exist, or to instead return Nothing and not throw an error. This of course could be a behaviour of the Expando, or alternatively a declaration made on the interface that the compiler would interpret.  The benefit of being on the interface is it would offer greater granularity.
Other parts to polish all this would be to perhaps have a DoesExist method, and rather than pass it a string for the property key, you could pass it NameOf(Person.DOB) or similar, thus allowing symbolic renaming to work throughout and avoiding the dreaded string literal issues that can occur with dynamic properties.
Filed under: , ,