Here's the deal:
I have a report designer where users can create reports based on some predefined datasets. They can select a set of columns to include in the report and then, when the report is ran, an IList is created by mapping the NHibernate collection over to the dto class collection using automapper.
The problem with this is that the DTO collection has a load of redundant columns in as it will be populated with all the data regardless of whether or not it's needed.
My solution to this? Why not create a DTO type at runtime, using the information we have and map the nhibernate collection to the dynamically created DTO collection using only the properties needed:
#region create a dto type:
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "tmpAssembly";
var assemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule");
// create a new type builder
TypeBuilder typeBuilder = module.DefineType("ReportDto", TypeAttributes.Public | TypeAttributes.Class);
foreach (var propertyName in propNames)
{
// Generate a private field
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
// Generate a public property
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None,
typeof(string),
new Type[] { typeof(string) });
// The property set and property get methods require a special set of attributes:
MethodAttributes GetSetAttr =
MethodAttributes.Public |
MethodAttributes.HideBySig;
// Define the "get" accessor method for current private field.
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
typeof(string),
Type.EmptyTypes);
// Intermediate Language stuff...
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
// Define the "set" accessor method for current private field.
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { typeof(string) });
// Again some Intermediate Language stuff...
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
// Last, we must map the two methods created above to our PropertyBuilder to
// their corresponding behaviors, "get" and "set" respectively.
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}
Type generetedType = typeBuilder.CreateType();
// Now we have our type. Let's create an instance from it:
object generetedObject = Activator.CreateInstance(generetedType);
#endregion
Mapper.CreateMap(typeof(MainInvoiceDataSums), generetedType);
var dto =
Mapper.Map<IList<MainInvoiceDataSums>, IList<generetedType>>(r);
The problem?
var dto =
Mapper.Map<IList<MainInvoiceDataSums>, IList<generetedType>>(r);
We can't new up an IList using the generated type as the generic parameter :s
I seem to always run into problems like this. Am I abusing generics? Is this possible? It would make the app a lot faster (once caching and some checks to dissalow the temp assembly to be regenerated etc are added) and a lot less fussy to maintain.
w://
We can't ne up an IList using the generated type as the generic parameter :s
I seem to always run into problems like this. Am I abusing generics? Is this possible? It would make the app a lot faster (once caching and some checks to dissalow the temp assembly to be regenerated etc are added) and a lot less fussy to maintain.
w://