c# - Expression for read from property and write to private readonly field -


it long story ): have types this:

public class model {     private readonly sometype _member;     private readonly anothertype _member2;     public model(sometype member, anothertype member2) {         _member = member;         _member2 = member2;     }     public sometype member { { return _member; } }     public anothertype member2 { { return _member2; } } } 

i'm trying create expressions create instance of class, reads properties other objects (anon objects usually), , write values created instance's private fields -based on shown naming convention: prop has field name: _prop.

i mean want write below objects new instance of model:

var anon1 = new { member = "something" }; // expected: new model _member = "something"  var anon2 = new { member2 = "something" }; // expected: new model _member2 = "something"  var anon3 = new { member = "something", member2 = "something else" }; // expected: new model _member = "something" , _member2 = "something else" 

i have created below code, creates new instances, nothing fields. can me find did wrong please?

public class instancecreator {      static public readonly func<fieldinfo, propertyinfo, bool> namingconvention;      static instancecreator() {         namingconvention = (f, p) => {             var startswithunderscope = f.name.startswith("_");             var hassamename = p.name.equals(f.name.remove(0, 1), stringcomparison.ordinalignorecase);             var hassametype = f.fieldtype == p.propertytype;             return startswithunderscope && hassamename && hassametype &&                    f.isinitonly && !p.canwrite;         };     }      private readonly type _type;     private readonly func<dynamic, dynamic> _creator;      public instancecreator(type type) {         _type = type;         var ctor = getctor(type);         var propertytofieldwriters = makewriters(type);         _creator = makecreator(type, ctor, propertytofieldwriters);     }      private expression getctor(type type) {         if (type == typeof(string)) // ctor string             return expression.lambda<func<dynamic>>(                 expression.constant(string.empty));         if (type.isvaluetype || // type has parameterless ctor             type.getconstructor(type.emptytypes) != null)             return expression.lambda<func<dynamic>>(expression.new(type));         var info = typeof(formatterservices).getmethod("getuninitializedobject");         var call = expression.call(info, expression.constant(type));         return call;         //return expression.lambda<func<dynamic>>(call);     }      private ienumerable<propertytofieldmapper> makewriters(type type) {         var properties = type.getproperties(bindingflags.instance | bindingflags.public);         var fields = type.getfields(bindingflags.instance | bindingflags.nonpublic);         var list = (from field in fields                     let property = properties.firstordefault(prop => namingconvention(field, prop))                     property != null                     select new propertytofieldmapper(field, property)).tolist();         foreach (var item in list) {             var sourceparameter = expression.parameter(type, "sourceparameter");             var propertygetter = expression.property(sourceparameter, item.property.name);             var targetparameter = expression.parameter(type, "targetparameter");             var setterinfo = item.field.gettype().getmethod("setvalue", new[] { typeof(object), typeof(object) });             var settercall = expression.call(expression.constant(item.field), setterinfo,                 new expression[] {                                      expression.convert(targetparameter,typeof(object)),                                       expression.convert(propertygetter,typeof(object))                                  });             var call = expression.lambda(settercall, new[] { targetparameter, sourceparameter });             item.call = call;         }         return list;     }      private func<dynamic, dynamic> makecreator(         type type, expression ctor,         ienumerable<propertytofieldmapper> writers) {          var list = new list<expression>();          // creating new target         var targetvariable = expression.variable(type, "targetvariable");         list.add(expression.assign(targetvariable, expression.convert(ctor, type)));          // find properties in incoming data         var sourceparameter = expression.parameter(typeof(object), "sourceparameter");         var sourcetypevariable = expression.variable(typeof(type));         var sourcetypegetter = expression.call(sourceparameter, "gettype", type.emptytypes);         list.add(expression.assign(sourcetypevariable, sourcetypegetter));         var sourcepropertiesvariable = expression.variable(typeof(propertyinfo[]));         var sourcepropertiesgetter = expression.call(sourcetypevariable, "getproperties", type.emptytypes);         list.add(expression.assign(sourcepropertiesvariable, sourcepropertiesgetter));          // itrate on writers , add call block         foreach (var writer in writers) {             var param = expression.parameter(typeof(propertyinfo));             var prop = expression.property(param, "name");             var eq = expression.equal(expression.constant(writer.property.name), prop);             var = callany.call(sourcepropertiesvariable, expression.lambda(eq, param));             var predicate = expression.ifthen(any,                 expression.lambda(writer.call, new[] { targetvariable, sourceparameter }));             list.add(predicate);         }          list.add(targetvariable);          var block = expression.block(new[] { targetvariable, sourcetypevariable, sourcepropertiesvariable }, list);          var lambda = expression.lambda<func<dynamic, dynamic>>(             block, new[] { sourceparameter }             );          return lambda.compile();     }      public dynamic create(dynamic data) {         return _creator.invoke(data);     }      private class propertytofieldmapper {          private readonly fieldinfo _field;         private readonly propertyinfo _property;          public propertytofieldmapper(fieldinfo field, propertyinfo property) {             _field = field;             _property = property;         }          public fieldinfo field {             { return _field; }         }          public propertyinfo property {             { return _property; }         }          public expression call { get; set; }     } } 

also, have callany class, created here.

public class callany {      public static expression call(expression collection, expression predicate) {         type ctype = getienumerableimpl(collection.type);         collection = expression.convert(collection, ctype);          type elemtype = ctype.getgenericarguments()[0];         type predtype = typeof(func<,>).makegenerictype(elemtype, typeof(bool));          // enumerable.any<t>(ienumerable<t>, func<t,bool>)         var anymethod = (methodinfo)             getgenericmethod(typeof(enumerable), "any", new[] { elemtype },                 new[] { ctype, predtype }, bindingflags.static);          return expression.call(anymethod, collection, predicate);     }      static methodbase getgenericmethod(type type, string name, type[] typeargs, type[] argtypes, bindingflags flags) {         int typearity = typeargs.length;         var methods = type.getmethods()             .where(m => m.name == name)             .where(m => m.getgenericarguments().length == typearity)             .select(m => m.makegenericmethod(typeargs));          return type.defaultbinder.selectmethod(flags, methods.toarray(), argtypes, null);     }      static type getienumerableimpl(type type) {         // ienumerable implementation. either type ienumerable<t> t,          // or implements ienumerable<t> t. need find interface.         if (isienumerable(type))             return type;         type[] t = type.findinterfaces((m, o) => isienumerable(m), null);         debug.assert(t.length == 1);         return t[0];     }      static bool isienumerable(type type) {         return type.isgenerictype             && type.getgenerictypedefinition() == typeof(ienumerable<>);     } } 

and here usage:

var inst = new instancecreator(typeof (model)).create(new {mydata}); 

well, found problem. should use expandoobject instead of dynamic keyword. , pass logic idictionary<string, object>. here solution:

public class instancecreator {      static public readonly func<fieldinfo, propertyinfo, bool> namingconvention;      static instancecreator() {         namingconvention = (f, p) => {             var startswithunderscope = f.name.startswith("_");             var hassamename = p.name.equals(f.name.remove(0, 1), stringcomparison.ordinalignorecase);             var hassametype = f.fieldtype == p.propertytype;             return startswithunderscope && hassamename && hassametype &&                    f.isinitonly && !p.canwrite;         };     }      private readonly type _type;     private readonly func<idictionary<string, object>, dynamic> _creator;      public instancecreator(type type) {         _type = type;         var ctor = getctor(type);         var propertytofieldmappers = makemappers(type);         _creator = makecreator(type, ctor, propertytofieldmappers);     }      private expression getctor(type type) {         if (type == typeof(string)) // ctor string             return expression.lambda<func<dynamic>>(                 expression.constant(string.empty));         if (type.isvaluetype || // type has parameterless ctor             type.getconstructor(type.emptytypes) != null)             return expression.lambda<func<dynamic>>(expression.new(type));         var info = typeof(formatterservices).getmethod("getuninitializedobject");         return expression.call(info, expression.constant(type));     }      private ienumerable<propertytofieldmapper> makemappers(type type) {         var properties = type.getproperties(bindingflags.instance | bindingflags.public);         var fields = type.getfields(bindingflags.instance | bindingflags.nonpublic);         var list = field in fields                     let property = properties.firstordefault(prop => namingconvention(field, prop))                     property != null                     select new propertytofieldmapper(field, property);         return list;     }      private func<idictionary<string, object>, dynamic> makecreator(         type type, expression ctor,         ienumerable<propertytofieldmapper> maps) {          var list = new list<expression>();         var vlist = new list<parameterexpression>();          // creating new target         var targetvariable = expression.variable(type, "targetvariable");         vlist.add(targetvariable);         list.add(expression.assign(targetvariable, expression.convert(ctor, type)));          // accessing source         var sourcetype = typeof(idictionary<string, object>);         var sourceparameter = expression.parameter(sourcetype, "sourceparameter");          // calling source containskey(string) method         var containskeymethodinfo = sourcetype.getmethod("containskey", new[] { typeof(string) });          var accesssourceindexerprop = sourcetype.getproperty("item");         var accesssourceindexerinfo = accesssourceindexerprop.getgetmethod();          // itrate on writers , add call block         var containskeymethodargument = expression.variable(typeof(string), "containskeymethodargument");         vlist.add(containskeymethodargument);         foreach (var map in maps) {             list.add(expression.assign(containskeymethodargument, expression.constant(map.property.name)));             var containskeymethodcall = expression.call(sourceparameter, containskeymethodinfo,                                                         new expression[] { containskeymethodargument });              // creating writer             var sourcevalue = expression.call(sourceparameter, accesssourceindexerinfo,                                               new expression[] { containskeymethodargument });             var setterinfo = map.field.gettype().getmethod("setvalue", new[] { typeof(object), typeof(object) });             var settercall = expression.call(expression.constant(map.field), setterinfo,                 new expression[] {                                      expression.convert(targetvariable,typeof(object)),                                      expression.convert(sourcevalue,typeof(object))                                  });             list.add(expression.ifthen(containskeymethodcall, settercall));         }         list.add(targetvariable);          var block = expression.block(vlist, list);          var lambda = expression.lambda<func<idictionary<string, object>, dynamic>>(             block, new[] { sourceparameter }             );          return lambda.compile();     }      public dynamic create(idictionary<string, object> data) {         return _creator.invoke(data);     }      private class propertytofieldmapper {          private readonly fieldinfo _field;         private readonly propertyinfo _property;          public propertytofieldmapper(fieldinfo field, propertyinfo property) {             _field = field;             _property = property;         }          public fieldinfo field {             { return _field; }         }          public propertyinfo property {             { return _property; }         }     } } 

Comments

Popular posts from this blog

python - How to create a legend for 3D bar in matplotlib? -

java - Multi-Label Document Classification -

php - Dynamic url re-writing using htaccess -