3

I'm making a Portable Class Library (PCL) in .NET and it happens that, when trying to abstract any behavior, I face the very common annoyance that .NET Framework is very possessive with its types and interfaces. It's very usual to find a type doesn't implement any interface, or when it does, the interface is internal.

When existing types have compatible methods (same name and signature) it's rather easy: I have been using ImpromptuInterface like this:

nakedInstanceTheDoesNotImplementAnything.ActAs<MyBeautifulInterface>();

and I get exactly what I want. Transparent and handy.

But, what to do when some methods are slightly different?

  • Different names
  • Different call site: one is a property getter and the other is a method
  • Some methods that are different, but easily adaptable between them with minor modifications.

Normally, a pure OOP approach is recommended and we are told to create and Adapter. But when you have to adapt a complex hierarchy of types, this can be really tedious and complex as well, even more when you have HUGE classes like UIElement, Control, FrameworkElement…

The question is: Can I make ImpromptuInterface overcome those variations in the types to dynamically create adapters?

SuperJMN
  • 13,110
  • 16
  • 86
  • 185
  • Do you really have that many situations where you _need_ to do this? I mean situations where you cannot proceed without using interfaces this way. – John Saunders Feb 06 '14 at 20:51
  • Sure it's not the 99% of situations a developer has to face, but in my case, I'm developing a Visual Designer (https://github.com/SuperJMN/VisualDesigner) that needs to abstract controls. Also, types like Rect, Point, Vector are examples of types that don't exist in PCLs, so, if you want to make abstractions of them, you have to make a lot of extra classes that don't offer anything. Another example is this project (Avalonia https://github.com/grokys/Avalonia). The owner also misses a design with enough interfaces, and more open. It would make things easier. – SuperJMN Feb 06 '14 at 21:36
  • You might consider code generation using T4 templates. The templates could be driven off of some simple data source like an XML file, or even a CSV file. – John Saunders Feb 06 '14 at 21:39
  • Although the use of T4 templates would help here, it relies onto a totally different concept, not language mechanisms. I thought of a dynamic way of doing it. – SuperJMN Feb 07 '14 at 08:47
  • "Writing custom adapters for interface duck typing", might have been a better title, SO'ers tend to close things that look like your asking for 3rd party lib suggestion, otherwise I see nothing wrong with this question since it's about impromptu-interface--as tagged. – jbtule Feb 10 '14 at 15:11
  • 1
    I think that now it's pretty clear what I'm asking for. Dynamic adapters. ImpromptyInterface does it when everything fits in. But what if there are differences? – SuperJMN Feb 12 '14 at 11:53

1 Answers1

2

So ImpromtuInterface uses the DLR, basically when you call ActLike() it emits and caches a proxy for that interface, and wraps it around your object.

public class Proxy:IMyInterface {

      dynamic target;

      public int Foo(){
           return (int)target.Foo()
      } 
}

Since it's a dynamic invocation, you don't actually have the method on your target if it's and IDynamicMetaObjectProvider the most popular to customize being System.Dynamic.DynamicObject.

public class RoughDynamicAdapter:DynamicObject{

    public override bool TryInvokeMember(InvokeMemberBinder binder,
                                        Object[] args,
                                        out Object result){

          if(binder.Name == "Foo"){
            result = /* do your own logic */
            return true;
          }
          result = null;
          return false;
    }
}

But this is a lot of work, because it you have to handle the non modified calls as much as the modified calls.

There are several prefab DynamicObjects in ImpromptuInterface that I've moved to a separate library Dynamitey.

One in particular, BaseForwarder sounds like what you want, because rather than handing all the logic, forwarding the message to a target object is already implemented as the base functionality.

public class DynamicAdapter:Dynamitey.DynamicObjects.BaseForwarder {

     public DynamicAdapter(object target):base(target){
     }

     public override bool TryInvokeMember(InvokeMemberBinder binder,
                                         Object[] args,
                                        out Object result){
          var newName = binder.Name;
          if(newName == "Foo"){
             result = Dynamic.InvokeMember(CallTarget, "Bar", args)
             return true;
          }
          //else pass them method on as it was called
          return base.TryInvokeMember(binder, args, out result)
    }
}

Then to use it would be new DynamicAdapter(myObject).ActLike<IMyInterface>()

jbtule
  • 31,383
  • 12
  • 95
  • 128