I've ran into a problem and wondered if there's simple way of solving it.
Here I have a XML template, defining some properties and their values.
<Properties>
<Property name="ID">10000</Property>
<Property name="Name">
<SubProperty name="FirstName">Foo</SubProperty>
<SubProperty name="LastName">Bar</SubProperty >
</Property>
</Properties>
All I what is to extract the Properties/subProperties defined in the template to generate a new XML file, with all values attached, something like
<Items>
<ID>10000</ID>
<Name>
<FirstName>Foo</FirstName>
<LastName>Bar</LastName>
</Name>
</Items>
Since I don't know the content of the template in design time, I tried to load it and created a List class use LINQ, but cannot get the result above when serialize it directly. So instead of create a List class I created a dynamic object using Reflection.Emit and then serialize the object to XML.
private static readonly XDocument doc = XDocument.Load("Template.xml");
static void Main(string[] args) {
var newType = CreateDynamicType();
var newObject = Activator.CreateInstance(newType);
var properties = newType.GetProperties();
foreach (var property in properties) {
// assign values
}
SerializeToXml(newObject);
}
private static Type CreateDynamicType() {
AssemblyName assemblyName = new AssemblyName() { Name = "DynamicTypeAdapter" };
AssemblyBuilder assembly =
Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder module =
assembly.DefineDynamicModule(assembly.GetName().Name, false);
TypeBuilder type = module.DefineType("Items", TypeAttributes.Public | TypeAttributes.Class);
foreach (var p in doc.Descendants("Property")) {
string pName = p.Attribute("name").Value;
TypeBuilder subType = module.DefineType(pName, TypeAttributes.Public | TypeAttributes.Class);
foreach (var sp in p.Descendants("SubProperty")) {
CreateDynamicProperty(subType, sp.Attribute("name").Value, typeof(string));
}
var propertyType = subType.CreateType();
CreateDynamicProperty(type, pName, propertyType);
}
return type.CreateType();
}
private static void CreateDynamicProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType) {
PropertyBuilder property = typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None, propertyType, new Type[] { typeof(string) });
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.HideBySig;
MethodBuilder getMethod =
typeBuilder.DefineMethod("get_value", GetSetAttributes, propertyType, Type.EmptyTypes);
ILGenerator getIL = getMethod.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, field);
getIL.Emit(OpCodes.Ret);
MethodBuilder setMethod =
typeBuilder.DefineMethod("set_value", GetSetAttributes, null, new Type[] { typeof(string) });
ILGenerator setIL = setMethod.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, field);
setIL.Emit(OpCodes.Ret);
property.SetGetMethod(getMethod);
property.SetSetMethod(setMethod);
}
It works fine but is there any simple way of doing this? Any comment is appreciated. Thanks