Project Description
Simple framework for runtime type adaptations.


For information on the adapter design pattern see: http://en.wikipedia.org/wiki/Adapter_pattern

This library provides a single registry for type adapters and with it forms a composed adapter. Using this composed adapter objects can be adapted in a cast like style. Like:

    //--------Bootstrapping--------
    var adaptionFunc = 
        new Func<MyType,IRequieredInterface>( o => new RequiredInterfaceImp(o) );
    var adapters = Adapters.CreateComposed( new[] { Adapter.FromFunc( adaptionFunc ) } );

    //--------Usage--------
    var instance = new MyType();
    var adapted = adapters.Cast<IRequiredInterface>(instance);


The composed adapter can chain individual adapter methods to perform more complex adaptations. For example an adapter O => IA and an adapter IA => IB can be registered. The composed adapter can now adapt an instance of O to an IB interface in one single statement.

    //--------Bootstrapping--------
    var adapters = 
        Adapters.CreateComposed( 
            new[] { 
                Adapter.FromFunc( (O o) => (IA)new IaImp(o) ),            //(1)
                Adapter.FromFunc( (IA a) => (IB)ibFactory.Create(a) )     //(2)
            } 
        );

    //--------Usage--------
    var instance = new O();
    var adapted = adapters.Cast<IB>(instance);    //first invokes (1) and then (2)


It is also possible to register adaptations having multiple requirements. For example:
O => IA, O => IB and (IA, IB) => IC. The composed adapter can now adapt an instance of type O to an IC interface in one statement.

    //--------Bootstrapping--------
    var adapters = 
        Adapters.CreateComposed( 
            new[] { 
                Adapter.FromFunc( (O o) => (IA)new IaImp(o) ),                    //(1)
                Adapter.FromFunc( (O o) => (IB)ibFactory.Create(o) )              //(2)
                Adapter.FromFunc( (IA a, IB b) => (IC)new CImp { A = a, B = b } ) //(3)
            } 
        );

    //--------Usage--------
    var instance = new O();
    var adapted = adapters.Cast<IC>(instance);    //first invokes (1) and (2) then (3)



For each adaptation the composed adapter will remember the original object. If an adaptation itself is ever adapted the composed adapter will always start from the original object. This guarantees maximum reach for the composed adapter. For example:
O => IA, O => IB. There is no direct path from an IA object to IB so the following is not possible:
    //--------Bootstrapping--------
    var adapters = 
        Adapters.CreateComposed( 
            new[] { 
                Adapter.FromFunc( (O o) => (IA)new IaImp(o) ),            
                Adapter.FromFunc( (O o) => (IB)ibFactory.Create(o) )    
            } 
        );

    //--------Usage--------
    var instance = new IaImp(new O());
    var adapted = adapters.Cast<IB>(instance);    //Result null. No path from IA to IB


However; the following is possible:
    //--------Bootstrapping--------
    var adapters = 
        Adapters.CreateComposed( 
            new[] { 
                Adapter.FromFunc( (O o) => (IA)new IaImp(o) ),            
                Adapter.FromFunc( (O o) => (IB)ibFactory.Create(o) )    
            } 
        );

    //--------Usage--------
    var oInstance = new O();

    //Registers oInstance a original source for aAdapted.
    var aAdapted = adapters.Cast<IA>(oInstance);

    //First finds original source (oInstance) and converts that to IB.
   //Then sets oInstance as original source of bAdapted.
    var bAdapted = adapters.Cast<IB>(aAdapted);  


This original object can also be used for identity tests and can be found using the GetBase() method of the composed adapter. Using the above example:
    //Will pass
    Debug.Assert(
        object.ReferenceEquals(
            adapters.GetBase(aAdapted), 
            adapters.GetBase(bAdapted)
        )
    );

    //Or..

    var baseEC = adapters.GetEqualityComparer();

    //Will pass
    Debug.Assert(baseEC.Equals(aAdapted, bAdapted));


An object can always be cast to a type it itself implements.

Last edited Jul 4, 2014 at 3:43 PM by Throb, version 9