c# - Duck Typing DynamicObject derivate -
i wrote class allows derivate specify of properties can lazy loaded. code is:
public abstract class selfhydratingentity<t> : dynamicobject t : class { private readonly dictionary<string, loadablebackingfield> fields; public selfhydratingentity(t original) { this.original = original; this.fields = this.getbackingfields().todictionary(f => f.name); } public t original { get; private set; } protected virtual ienumerable<loadablebackingfield> getbackingfields() { yield break; } public override bool trygetmember(getmemberbinder binder, out object result) { loadablebackingfield field; if (this.fields.trygetvalue(binder.name, out field)) { result = field.getvalue(); return true; } else { var getter = propertyaccessor.getgetter(this.original.gettype(), binder.name); result = getter(this.original); return true; } } public override bool trysetmember(setmemberbinder binder, object value) { loadablebackingfield field; if (this.fields.trygetvalue(binder.name, out field)) { field.setvalue(value); return true; } else { var setter = propertyaccessor.getsetter(this.original.gettype(), binder.name); setter(this.original, value); return true; } } }
and derivate class:
public class selfhydratingperson : selfhydratingentity<iperson> { private readonly idatarepository datarepository; public selfhydratingderivate(idatarepository datarepository, iperson person) : base(person) { this.datarepository = datarepository } protected override ienumerable<loadablebackingfield> getbackingfields() { yield return new loadablebackingfield("address", () => this.datarepository.addresses.get(this.original.addressid)); } }
this works fine getting , settings property values, either runtimebinderexception when implicitly cast or invalidcastexception explicitly cast selfhydratingentity t.
i know can override dynamicobject.tryconvert method, i'm wondering what put in method. i've read lot duck typing today, , have tried out several libraries, none of them work particular scenario. of libraries i've tried today generate wrapper class using reflection.emit makes calls "get_" , "set_" methods , naturally use reflection find these methods on wrapped instance. selfhydratingentity of course doesn't have "get_" , "set_" methods defined.
so, i'm wondering if kind of thing possible. there way cast instance of selfhydratingentity t? i'm looking this:
var original = getoriginalperson(); dynamic person = new selfhydratingperson(new datarepository(), original); string name = person.name; // gets property value on original var address = person.address; // gets property value using loadablebackingfield registration var iperson = (iperson)person; - or - var iperson = ducktype.as<iperson>(person);
have seen duck typing project. looks pretty good. have found great example mauricio. uses windsor castle dynamic proxy intercept method calls
using code mauricio following code works dream
class program { static void main(string[] args) { dynamic person = new { name = "peter" }; var p = ducktype.as<iperson>(person); console.writeline(p.name); } } public interface iperson { string name { get; set; } } public static class ducktype { private static readonly proxygenerator generator = new proxygenerator(); public static t as<t>(object o) { return generator.createinterfaceproxywithouttarget<t>(new ducktypinginterceptor(o)); } } public class ducktypinginterceptor : iinterceptor { private readonly object target; public ducktypinginterceptor(object target) { this.target = target; } public void intercept(iinvocation invocation) { var methods = target.gettype().getmethods() .where(m => m.name == invocation.method.name) .where(m => m.getparameters().length == invocation.arguments.length) .tolist(); if (methods.count > 1) throw new applicationexception(string.format("ambiguous method match '{0}'", invocation.method.name)); if (methods.count == 0) throw new applicationexception(string.format("no method '{0}' found", invocation.method.name)); var method = methods[0]; if (invocation.genericarguments != null && invocation.genericarguments.length > 0) method = method.makegenericmethod(invocation.genericarguments); invocation.returnvalue = method.invoke(target, invocation.arguments); } }
Comments
Post a Comment