Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:
1) Очень быстрая. Работает через Emit с производительностью рукописного кода. По разным тестам в 150-600 раз быстрее чем AutoMapper. Бенчмарк
2) Очень гибкая. Проецировать можно что угодно на что угодно. Например, датаридер на объекты, объекты на SQL команды (UPDATE, INSERT), объекты на строку (сериализация), строку на объекты (десериализация) и так далее. Короче говоря, в рантайме можно задать произвольный меппинг чего угодно на что угодно, который работает со скоростью рукописного кода.
Здравствуйте, mrTwister, Вы писали:
T>http://emitmapper.codeplex.com
T>Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:
Всё понравилось, кроме того как вы сделали Ignoring members
имхо писать имена как простая строка это плохой моветон.
Я бы добавил ещё атрибуты для полей которые не надо копировать.
var a = ObjectsMapperManager.DefaultInstance.GetMapper<B, A>(
new DefaultMapConfig().IgnoreMembers<B, A>(new[]{"str1"})
).Map(new B());
Кстати, под Silverlight работает? Если нет, опять большой минус.
Здравствуйте, mrTwister, Вы писали:
T>http://emitmapper.codeplex.com
T>Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:
T>1) Очень быстрая. Работает через Emit с производительностью рукописного кода. По разным тестам в 150-600 раз быстрее чем AutoMapper. Бенчмарк
T>2) Очень гибкая. Проецировать можно что угодно на что угодно. Например, датаридер на объекты, объекты на SQL команды (UPDATE, INSERT), объекты на строку (сериализация), строку на объекты (десериализация) и так далее. Короче говоря, в рантайме можно задать произвольный меппинг чего угодно на что угодно, который работает со скоростью рукописного кода.
Здравствуйте, Tom, Вы писали:
Tom>А в каких случаях это вообще надо использовать? Почему просто не генерить C# код?
В случаях когда мне не надо что-бы значение из определёного свойства копировалось в другой обьект.
Здравствуйте, Holms, Вы писали: H>Всё понравилось, кроме того как вы сделали Ignoring members H>имхо писать имена как простая строка это плохой моветон. H>Я бы добавил ещё атрибуты для полей которые не надо копировать.
H>
H>var a = ObjectsMapperManager.DefaultInstance.GetMapper<B, A>(
H> new DefaultMapConfig().IgnoreMembers<B, A>(new[]{"str1"})
H> ).Map(new B());
H>
Имхо, заставлять вешать атрибуты — это еще больший моветон. Это примерно как заставлять наследоваться от специального класса. Тем более, что ничто не мешает реализовать требуемую функциональность своими силами на основе Emit Mapper. Самый простой путь — это тупо отнаследоваться от DefaultMapConfig и переопределить логику игнора с учетом своих собственных требований и пожеланий (это могут быть не только атрибуты):
// Это наш собственный атрибут. Нас никто не заставляет использовать атрибуты, но допустим удобней/привычнее
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class MyIgnoreAttribute : Attribute
{
}
// Класс-оригиналpublic class IgnoreByAttributesSrc
{
// Делаем так, чтобы первое поле не копировалось
[MyIgnoreAttribute]
public string str1 = "IgnoreByAttributesSrc::str1";
public string str2 = "IgnoreByAttributesSrc::str2";
}
// Класс-копияpublic class IgnoreByAttributesDst
{
public string str1 = "IgnoreByAttributesDst::str1";
public string str2 = "IgnoreByAttributesDst::str2";
}
public class MyConfigurator : DefaultMapConfig
{
//Переопределяем метод, который вызывается для конфигурирования меппинга и добавляем вызов IgnoreMembers
//в соответствии с нашей логикой - атрибутомpublic override IMappingOperation[] GetMappingOperations(Type from, Type to)
{
base.IgnoreMembers<object, object>(GetIgnoreFields(from).Concat(GetIgnoreFields(to)).ToArray());
return base.GetMappingOperations(from, to);
}
//Метод возвращает список полей и свойств, помеченных атрибутомprivate IEnumerable<string> GetIgnoreFields(Type type)
{
return type
.GetFields()
.Where(
f => f.GetCustomAttributes(typeof(MyIgnoreAttribute), false).Length > 0
)
.Select(f => f.Name)
.Concat(
type
.GetProperties()
.Where(
p => p.GetCustomAttributes(typeof(MyIgnoreAttribute), false).Length > 0
)
.Select(p => p.Name)
);
}
}
[TestMethod]
public void Test()
{
var mapper = ObjectsMapperManager.DefaultInstance.GetMapper<IgnoreByAttributesSrc, IgnoreByAttributesDst>(new MyConfigurator());
var dst = mapper.Map(new IgnoreByAttributesSrc());
Assert.AreEqual("IgnoreByAttributesDst::str1", dst.str1);
Assert.AreEqual("IgnoreByAttributesSrc::str2", dst.str2);
}
Короче говоря, при проектировании Emit Mapper делалась ставка на то, что у каждого есть свое мнение на то, как должна выглядеть идеальная библиотека для маппинга. И вместо предоставления швейцарского ножа с миллионом возможностей включая заваривание кофе, Emit Mapper предоставляет своего рода фреймворк, который каждый может использовать для построения маппинга с учетом своих собственных требований. В семплах есть пример, когда генерируется маппер для объектов на дбридер используя штатные механизмы расширения. В этом основная "фишка" библиотеки.
Здравствуйте, koandrew, Вы писали:
K>Бегло просмотрел. Вывод — BLToolkit круче
Только это разные вещи. Emit Mapper — это библиотека, которую можно использовать для разработки своего собственного BLToolkit с учетом своих собственных требований и пожеланий. Примеры меппинга для DbDataReader и DbCommand приведены исключительно для демонстрации возможностей.
T>Имхо, заставлять вешать атрибуты — это еще больший моветон. Это примерно как заставлять наследоваться от специального класса. Тем более, что ничто не мешает реализовать требуемую функциональность своими силами на основе Emit Mapper. Самый простой путь — это тупо отнаследоваться от DefaultMapConfig и переопределить логику игнора с учетом своих собственных требований и пожеланий (это могут быть не только атрибуты):
ага ясно, ну тогда хорошо.
еще-бы подержку Silverlight-а добавили и было бы всё пучком
K>Всё будет
то что будет для SL + LINQ + code generation tool никто не сомневается, мне щас надо, поэтому остановился пока на SubSonic (осбенно мне нравится генериция ДБ обьектов из моих C# классов).
Здравствуйте, Holms, Вы писали:
H>то что будет для SL + LINQ
Над этим работают H>+ code generation tool
Вряд ли будет, ибо свой тул с таким функционалом пишется за полчаса-час.
Здравствуйте, mrTwister, Вы писали:
T>Только это разные вещи. Emit Mapper — это библиотека, которую можно использовать для разработки своего собственного BLToolkit с учетом своих собственных требований и пожеланий. Примеры меппинга для DbDataReader и DbCommand приведены исключительно для демонстрации возможностей.
Вообще-то БЛТ в первую очередь маппер, а у же потом всё остальное. Вот автор увидит топик и расскажет подробнее
Здравствуйте, koandrew, Вы писали:
K>Вообще-то БЛТ в первую очередь маппер, а у же потом всё остальное. Вот автор увидит топик и расскажет подробнее
Как раз как маппер, БЛТ довольно слабый (ценность БЛТ не в маппере). Он не поддерживает даже вложенные объекты, не конфигурируется и т.д. По крайней мере не справился даже с такой простой задачкой:
public class Destination
{
public class Int
{
public string str2;
}
public string str1;
public Int i;
}
public class Source
{
public class Int
{
public string str2 = "B1::Int::str2";
}
public string str1 = "B1::str1";
public Int i = new Int();
}
Да и производительность у БЛТ маппера оставляет желать лучшего. На простеньком тесте (класс без вложеных объектов) БЛТ оказался в 250 раз медленнее. Вот код теста:
public class A2
{
public string str1;
public string str2;
public string str3;
public string str4;
public string str5;
public string str6;
public string str7;
public string str8;
public string str9;
public int n1;
public int n2;
public int n3;
public int n4;
public int n5;
public int n6;
public int n7;
}
public class B2
{
public string str1 = "str1";
public string str2 = "str2";
public string str3 = "str3";
public string str4 = "str4";
public string str5 = "str5";
public string str6 = "str6";
public string str7 = "str7";
public string str8 = "str8";
public string str9 = "str9";
public int n1 = 1;
public long n2 = 2;
public short n3 = 3;
public byte n4 = 4;
public decimal n5 = 5;
public float n6 = 6;
public int n7 = 7;
}
static long BenchBLToolkit_Simple(int mappingsCount)
{
var s = new B2();
var d = new A2();
d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < mappingsCount; ++i)
{
d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
static long EmitMapper_Simple(int mappingsCount)
{
var mapper = ObjectsMapperManager.DefaultInstance.GetMapper<B2, A2>();
var s = new B2();
var d = new A2();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < mappingsCount; ++i)
{
mapper.Map(s, d);
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
Здравствуйте, mrTwister, Вы писали:
T>Да и производительность у БЛТ маппера оставляет желать лучшего. На простеньком тесте (класс без вложеных объектов) БЛТ оказался в 250 раз медленнее. Вот код теста:
А ты не задумывался о том, что у BLT может быть ленивая генерация кода?
... << RSDN@Home 1.2.0 alpha 4 rev. 1324 on Windows 7 6.1.7600.0>>
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, mrTwister
А>Я хотел бы использовать EmitMapper для клонирования объектов. А>Маппер использую вот так:
А>
Здравствуйте, AndrewVK, Вы писали:
AVK>А ты не задумывался о том, что у BLT может быть ленивая генерация кода?
Задумывался. Именно по-этому в тесте есть строчка (выделено жирным):
static long BenchBLToolkit_Simple(int mappingsCount)
{
var s = new B2();
var d = new A2();
d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < mappingsCount; ++i)
{
d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);
}
sw.Stop();
return sw.ElapsedMilliseconds;
}