Passthrough Objects – Duck Typing++
- by EltonStoneman
[Source: http://geekswithblogs.net/EltonStoneman]
Can't see a genuine use for this, but I got the idea in my head and wanted to work it through. It's an extension to the idea of duck typing, for scenarios where types have similar behaviour, but implemented in differently-named members.
So you may have a set of objects you want to treat as an interface, which don't implement the interface explicitly, and don't have the same member names so they can't be duck-typed into implicitly implementing the interface. In a fictitious example, I want to call Get on whichever ICache implementation is current, and have the call passed through to the relevant method – whether it's called Read, Retrieve or whatever:
A sample implementation is up on github here: PassthroughSample.
This uses Castle's DynamicProxy behind the scenes in the same way as my duck typing sample, but allows you to configure the passthrough to specify how the inner (implementation) and outer (interface) members are mapped:
var setup = new Passthrough();
var cache = setup.Create("PassthroughSample.Tests.Stubs.AspNetCache, PassthroughSample.Tests")
.WithPassthrough("Name", "CacheName")
.WithPassthrough("Get", "Retrieve")
.WithPassthrough("Set", "Insert")
.As<ICache>();
- or using some ugly Lambdas to avoid the strings :
Expression<Func<ICache, string, object>> get = (o, s) => o.Get(s);
Expression<Func<Memcached, string, object>> read = (i, s) => i.Read(s);
Expression<Action<ICache, string, object>> set = (o, s, obj) => o.Set(s, obj);
Expression<Action<Memcached, string, object>> insert = (i, s, obj) => i.Put(s, obj);
ICache cache = new Passthrough<ICache, Memcached>()
.Create()
.WithPassthrough(o => o.Name, i => i.InstanceName)
.WithPassthrough(get, read)
.WithPassthrough(set, insert)
.As();
- or even in config:
ICache cache = Passthrough.GetConfigured<ICache>();
...
<passthrough>
<types>
<typename="PassthroughSample.Tests.Stubs.ICache, PassthroughSample.Tests"
passesThroughTo="PassthroughSample.Tests.Stubs.AppFabricCache, PassthroughSample.Tests">
<members>
<membername="Name"passesThroughTo="RegionName"/>
<membername="Get"passesThroughTo="Out"/>
<membername="Set"passesThroughTo="In"/>
</members>
</type>
Possibly useful for injecting stubs for dependencies in tests, when your application code isn't using an IoC container. Possibly it also has an alternative implementation using .NET 4.0 dynamic objects, rather than the dynamic proxy.