c# - Updating dynamically generated assembly -
i have following code dynamically generates assembly , classes based on edmmodel. working fine, bit confused on how can update assembly when model changes.
here current thoughts, either:
- update current classes, adding/removing properties. adding new classes when needed.
- create version of assembly, allowing me have 2 versions running @ same time (this approach preferable allow user access different versions of model, , mean current version still used while new 1 being generated)
is possible run 2 versions of same assembly way? possible update type has been created? doing right?
public class dynamicassembygenerator { private idictionary<string, assemblybuilder> _assemblybuilders; private idictionary<string, modulebuilder> _modulebuilders; private idictionary<string, typebuilder> _typebuilders; private idictionary<string, enumbuilder> _enumbuilders; private idictionary<string, type> _types; public void create(iedmmodel model) { _assemblybuilders = model.declarednamespaces.todictionary(declarednamespace => declarednamespace, createassemblybuilder); _modulebuilders = model.declarednamespaces.todictionary(declarednamespace => declarednamespace, declarednamespace => createmodulebuilder(declarednamespace, _assemblybuilders[declarednamespace])); _typebuilders = new dictionary<string, typebuilder>(); _enumbuilders = new dictionary<string, enumbuilder>(); _types = new dictionary<string, type>(); foreach ( var edmschemaelement in model.schemaelements.where(s => s.schemaelementkind == edmschemaelementkind.typedefinition)) { if (_modulebuilders.containskey(edmschemaelement.namespace)) { createtype(model, edmschemaelement.fullname(), _modulebuilders[edmschemaelement.namespace]); } } foreach (var assemblybuilder in _assemblybuilders.values) { assemblybuilder.save(assemblybuilder.getname().name + ".dll"); } foreach (var value in _types.values) { var edmtype = model.finddeclaredtype(value.fullname); model.setannotationvalue<clrtypeannotation>(edmtype, new clrtypeannotation(value)); } } private void createtype(iedmmodel model, string typename, modulebuilder modulebuilder) { if (_typebuilders.containskey(typename) || _enumbuilders.containskey(typename)) { return; } var structuredtype = model.finddeclaredtype(typename) iedmstructuredtype; if (structuredtype != null) { var entitytype = structuredtype iedmentitytype; var typebuilder = createtypebuilder(structuredtype, model, modulebuilder); _typebuilders.add(typename, typebuilder); var constructorbuilder = createconstructor(typebuilder); ilgenerator il = constructorbuilder.getilgenerator(); foreach (var edmproperty in structuredtype.declaredproperties) { createproperty(edmproperty, model, typebuilder, il, entitytype != null && entitytype.hasdeclaredkeyproperty(edmproperty)); } il.emit(opcodes.ret); _types.add(typename, typebuilder.createtype()); return; } var enumtype = model.finddeclaredtype(typename) iedmenumtype; if (enumtype != null) { var enumbuilder = createenumbuilder(typename, modulebuilder); _enumbuilders.add(typename, enumbuilder); foreach (var edmenummember in enumtype.members) { var value = edmenummember.value edmintegerconstant; if (value != null) { createenumvalue(edmenummember.name, convert.toint32(value.value), enumbuilder); } } _types.add(typename, enumbuilder.createtype()); return; } } private assemblybuilder createassemblybuilder(string assemblyname) { var appdomain = appdomain.currentdomain; var assemblybuilder = appdomain.definedynamicassembly(new assemblyname(assemblyname), assemblybuilderaccess.runandsave); return assemblybuilder; } private modulebuilder createmodulebuilder(string assemblyname, assemblybuilder assemblybuilder) { var modulebuilder = assemblybuilder.definedynamicmodule(assemblyname, assemblyname + ".dll"); return modulebuilder; } private typebuilder createtypebuilder(iedmstructuredtype type, iedmmodel model, modulebuilder modulebuilder) { var basetype = typeof(dynamicentitybase); if (type.basetype != null) { var propertytype = edmlibhelpers.getclrtype(type.basetype, model); if (propertytype == null) { var schemaelement = model.finddeclaredtype(type.basetype.fulltypename()); createtype(model, schemaelement.fullname(), _modulebuilders[schemaelement.namespace]); basetype = _types[schemaelement.fullname()]; } } return modulebuilder.definetype(type.fulltypename(), typeattributes.class | typeattributes.public, basetype); } private enumbuilder createenumbuilder(string typename, modulebuilder modulebuilder) { return modulebuilder.defineenum(typename, typeattributes.public, typeof(int)); } private void createenumvalue(string name, int value, enumbuilder enumbuilder) { enumbuilder.defineliteral(name, value); } private void createproperty(iedmproperty edmproperty, iedmmodel model, typebuilder typebuilder, ilgenerator constructorilgenerator, bool iskey) { var propertytype = getpropertytype(edmproperty, model); var propertyname = edmproperty.name; fieldbuilder ffirst; propertybuilder pfirst = createproperty(propertyname, propertytype, typebuilder, out ffirst); setdefaultvalue(edmproperty, model, ffirst, constructorilgenerator); if (iskey) { setpropertycustomattribute(pfirst, typeof(keyattribute)); } if (edmproperty.vocabularyannotations(model).any(v => v.term.fullname() == corevocabularyconstants.computed)) { setpropertycustomattribute(pfirst, typeof(computedattribute)); } if (edmproperty.propertykind == edmpropertykind.navigation) { if (edmproperty.type.iscollection()) { createproperty(propertyname + "ids", typeof(ilist<string>), typebuilder, out ffirst); var listtype = typeof(list<string>); constructorilgenerator.emit(opcodes.ldarg_0); constructorilgenerator.emit(opcodes.newobj, listtype.getconstructor(new type[0])); constructorilgenerator.emit(opcodes.stfld, ffirst); } else { createproperty(propertyname + "id", typeof(string), typebuilder, out ffirst); } } } private static propertybuilder createproperty(string propertyname, type propertytype, typebuilder typebuilder, out fieldbuilder fieldbuilder) { fieldbuilder = typebuilder.definefield("_" + propertyname, propertytype, fieldattributes.private); propertybuilder pfirst = typebuilder.defineproperty(propertyname, propertyattributes.hasdefault, propertytype, null); //getter methodbuilder mfirstget = typebuilder.definemethod("get_" + propertyname, methodattributes.public | methodattributes.specialname | methodattributes.hidebysig, propertytype, type.emptytypes); ilgenerator firstgetil = mfirstget.getilgenerator(); firstgetil.emit(opcodes.ldarg_0); firstgetil.emit(opcodes.ldfld, fieldbuilder); firstgetil.emit(opcodes.ret); //setter methodbuilder mfirstset = typebuilder.definemethod("set_" + propertyname, methodattributes.public | methodattributes.specialname | methodattributes.hidebysig, null, new type[] { propertytype }); ilgenerator firstsetil = mfirstset.getilgenerator(); firstsetil.emit(opcodes.ldarg_0); firstsetil.emit(opcodes.ldarg_1); firstsetil.emit(opcodes.stfld, fieldbuilder); firstsetil.emit(opcodes.ret); pfirst.setgetmethod(mfirstget); pfirst.setsetmethod(mfirstset); return pfirst; } private static void setpropertycustomattribute(propertybuilder propertybuilder, type attributetype) { var attributebuilder = new customattributebuilder(attributetype.getconstructor(new type[0]), new object[0]); propertybuilder.setcustomattribute(attributebuilder); } private type getpropertytype(iedmproperty edmproperty, iedmmodel model) { var edmpropertytype = getedmtype(edmproperty.type); var propertytype = edmlibhelpers.getclrtype(edmpropertytype, model); if (propertytype == null) { var schemaelement = model.finddeclaredtype(edmpropertytype.definition.fulltypename()); createtype(model, schemaelement.fullname(), _modulebuilders[schemaelement.namespace]); propertytype = _typebuilders[schemaelement.fullname()]; } if (edmproperty.type.iscollection()) { var listtype = typeof(ilist<>); propertytype = listtype.makegenerictype(propertytype); } return propertytype; } private iedmtypereference getedmtype(iedmtypereference type) { if (type.iscollection()) { var collectiontype = type.ascollection(); return collectiontype.collectiondefinition().elementtype; } else { return type; ; } } private void setdefaultvalue(iedmproperty property, iedmmodel model, fieldbuilder builder, ilgenerator constructorilgenerator) { if (!property.type.isnullable) { var propertytype = getpropertytype(property, model); if (property.type.iscomplex()) { constructorilgenerator.emit(opcodes.ldarg_0); constructorilgenerator.emit(opcodes.newobj, propertytype.getconstructor(new type[0])); constructorilgenerator.emit(opcodes.stfld, builder); } else if (property.type.iscollection()) { var listtype = typeof(list<>); var collectiontype = listtype.makegenerictype(propertytype.getgenericarguments()[0]); constructorilgenerator.emit(opcodes.ldarg_0); constructorilgenerator.emit(opcodes.newobj, collectiontype.getconstructor(new type[0])); constructorilgenerator.emit(opcodes.stfld, builder); } } } private constructorbuilder createconstructor(typebuilder typebuilder) { constructorbuilder constructor = typebuilder.defineconstructor( methodattributes.public | methodattributes.specialname | methodattributes.rtspecialname, callingconventions.standard, new type[0]); return constructor; } }
- update current classes, adding/removing properties.
not possible. once call typebuilder.createtype()
type created can't removed/modified.
- adding new classes when needed.
possible without problems. can use types define in assemblybuilder
without saving it, possible add new types.
- create version of assembly, allowing me have 2 versions running @ same time
no problem here.
- is possible run 2 versions of same assembly way?
it wouldn't same assembly .net... have in common? abstract concept "they same"? .net can't brain :-)
Comments
Post a Comment