简体   繁体   English

Automapper,泛型,dto funtimes

[英]Automapper, generics, dto funtimes

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. 他们可以选择要包含在报表中的一组列,然后在运行报表时,通过使用automapper将NHibernate集合映射到dto类集合来创建IList。

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. 这样做的问题是DTO集合中有一堆冗余列,因为它将填充所有数据,无论是否需要它。

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: 为什么不在运行时使用我们拥有的信息创建DTO类型,并仅使用所需的属性将nhibernate集合映射到动态创建的DTO集合:

#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 我们不能使用生成的类型作为泛型参数来新建IList: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 我们不能使用生成的类型作为泛型参数来建立IList: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:// 女://

got it!! 得到它了!!

dont call createmap passing the generic lists! 不要调用createmap传递通用列表!

MethodInfo createMap = createMapInfo.MakeGenericMethod(new Type[] { typeof(MainInvoiceDataSums), generetedType });

sorted!! 分类!

:) :)

w:// 女://

Why not use the non-generic version of Map? 为什么不使用非泛型版本的Map?

Mapper.Map(r, typeof(IList<MainInvoiceDataSums>), 
                       typeof(IList<>).MakeGenericType(new [] { generatedType });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM