One of the things that’s always bugged me when using Windows UI libraries like WinForms and WPF is the sheer number of members that pop up in intellisense for a control. The Button type in WPF has around 300 members and a total of 9 levels of inheritance making it hard to find the useful members. Or to put it another way the inherited members occlude the useful members:

The picture above shows what you actually see in the code completion box in the editor, however for a button you’re probably more interested in the Click event, but that’s several pages away.

Disinherit Type Provider

As a thought experiment I’ve implemented an F# Type Provider that hides type members after a specified level of inheritance:

In the picture above the members now almost fit in a single page. The last property, not visible here, is an extra property added by the type provider that provides all the hidden members for the instance:

Type Provider Implementation

Underneath the covers the type provider takes an assembly name as a static parameter and optionally the level of inheritance to expose.

[<Literal>] let name = @"PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" type WPF = Disinherited< name , level=1 > let button = WPF.Button()

The provider then reflects over the types in the assembly and creates a proxy type as a provided type and exposes members that are declared within the specified inheritance level.

To provide the member we simply create a corresponding provided member with an expression that evaluates to the underlying type’s member:

let addMember (def:ProvidedTypeDefinition) ty (mem:MemberInfo) = match mem.MemberType with | MemberTypes.Constructor -> let ci = mem :?> ConstructorInfo let c = ProvidedConstructor(toParams ci) c.InvokeCode <- fun args -> Expr.Coerce(Expr.NewObject(ci,args), typeof<obj>) def.AddMember(c) | MemberTypes.Field -> let fi = mem :?> FieldInfo let field = ProvidedField(mem.Name, fi.FieldType) def.AddMember(field) | MemberTypes.Property -> let pi = mem :?> PropertyInfo let prop = ProvidedProperty(mem.Name, pi.PropertyType) prop.GetterCode <- fun args -> Expr.PropertyGet(Expr.Coerce(args.[0],ty), pi) def.AddMember(prop) | MemberTypes.Event -> let ei = mem :?> EventInfo let ev = ProvidedEvent(mem.Name, ei.EventHandlerType) ev.AdderCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty),ei.GetAddMethod(), args.Tail) ev.RemoverCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty), ei.GetRemoveMethod(), args.Tail) def.AddMember(ev) | MemberTypes.Method -> let mi = mem :?> MethodInfo if not mi.IsSpecialName then let m = ProvidedMethod(mi.Name, toParams mi, mi.ReturnType) m.InvokeCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty), mi, args.Tail) def.AddMember(m) | _ -> ()

The entire provider is implemented in around 100 lines of code, I’d be interested to hear if anybody else finds it useful :)

Source code

The source is available on GitHub: https://github.com/ptrelford/Disinherit