Automapper, generics, dto funtimes - PullRequest
3 голосов
/ 18 ноября 2009

Вот сделка:

У меня есть дизайнер отчетов, в котором пользователи могут создавать отчеты на основе некоторых предопределенных наборов данных. Они могут выбрать набор столбцов для включения в отчет, а затем, когда отчет запускается, создается IList путем сопоставления коллекции NHibernate с коллекцией классов dto с помощью automapper.

Проблема заключается в том, что в коллекции DTO загружены избыточные столбцы, поскольку в нее будут включены все данные независимо от того, нужны они или нет.

Мое решение этого? Почему бы не создать тип 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);

Проблема?

var dto =
                Mapper.Map<IList<MainInvoiceDataSums>, IList<generetedType>>(r);

Мы не можем создать новый IList, используя сгенерированный тип в качестве универсального параметра: s

Кажется, я всегда сталкиваюсь с такими проблемами. Я злоупотребляю дженериками? Это возможно? Это сделало бы приложение намного быстрее (после добавления кеширования и некоторых проверок, чтобы отключить временную сборку, которая будет регенерирована и т. Д.) И намного менее суетливым в обслуживании.

ш: //

Мы не можем создать IList, используя сгенерированный тип в качестве универсального параметра: s

Кажется, я всегда сталкиваюсь с такими проблемами. Я злоупотребляю дженериками? Это возможно? Это сделало бы приложение намного быстрее (после добавления кеширования и некоторых проверок для исключения временной сборки, которая будет регенерирована и т. Д.) И намного менее суетливым в обслуживании.

ш: //

Ответы [ 2 ]

2 голосов
/ 28 ноября 2009

Почему бы не использовать неуниверсальную версию Map?

Mapper.Map(r, typeof(IList<MainInvoiceDataSums>), 
                       typeof(IList<>).MakeGenericType(new [] { generatedType });
2 голосов
/ 18 ноября 2009

понял !!

не вызывайте createmap, передавая общие списки!

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

отсортирован !!

:)

ш: //

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...