[ANN] Emit Mapper
От: mrTwister Россия  
Дата: 18.11.09 21:00
Оценка: 65 (9)
http://emitmapper.codeplex.com

Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:

1) Очень быстрая. Работает через Emit с производительностью рукописного кода. По разным тестам в 150-600 раз быстрее чем AutoMapper. Бенчмарк

2) Очень гибкая. Проецировать можно что угодно на что угодно. Например, датаридер на объекты, объекты на SQL команды (UPDATE, INSERT), объекты на строку (сериализация), строку на объекты (десериализация) и так далее. Короче говоря, в рантайме можно задать произвольный меппинг чего угодно на что угодно, который работает со скоростью рукописного кода.
лэт ми спик фром май харт
Re: [ANN] Emit Mapper
От: Holms США  
Дата: 18.11.09 21:35
Оценка: 6 (1)
Здравствуйте, 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 работает? Если нет, опять большой минус.
... << RSDN@Home 1.2.0 alpha 4 rev. 1253>>
The life is relative and reversible.
Re[2]: [ANN] Emit Mapper
От: Tom Россия http://www.RSDN.ru
Дата: 18.11.09 21:53
Оценка:
H>Всё понравилось, кроме того как вы сделали Ignoring members
А в каких случаях это вообще надо использовать? Почему просто не генерить C# код?
Народная мудрось
всем все никому ничего(с).
Re: [ANN] Emit Mapper
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 18.11.09 21:59
Оценка: +1 -1
Здравствуйте, mrTwister, Вы писали:

T>http://emitmapper.codeplex.com


T>Emit Mapper — это мощная легковесная библиотека для проецирования одних объектов на другие. Имеет следующие особенности:


T>1) Очень быстрая. Работает через Emit с производительностью рукописного кода. По разным тестам в 150-600 раз быстрее чем AutoMapper. Бенчмарк


T>2) Очень гибкая. Проецировать можно что угодно на что угодно. Например, датаридер на объекты, объекты на SQL команды (UPDATE, INSERT), объекты на строку (сериализация), строку на объекты (десериализация) и так далее. Короче говоря, в рантайме можно задать произвольный меппинг чего угодно на что угодно, который работает со скоростью рукописного кода.


Бегло просмотрел. Вывод — BLToolkit круче
[КУ] оккупировала армия.
Re[3]: [ANN] Emit Mapper
От: Holms США  
Дата: 18.11.09 22:14
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>А в каких случаях это вообще надо использовать? Почему просто не генерить C# код?

В случаях когда мне не надо что-бы значение из определёного свойства копировалось в другой обьект.
... << RSDN@Home 1.2.0 alpha 4 rev. 1253>>
The life is relative and reversible.
Re[2]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 18.11.09 22:14
Оценка: 9 (2) +1
Здравствуйте, 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 предоставляет своего рода фреймворк, который каждый может использовать для построения маппинга с учетом своих собственных требований. В семплах есть пример, когда генерируется маппер для объектов на дбридер используя штатные механизмы расширения. В этом основная "фишка" библиотеки.
лэт ми спик фром май харт
Re[2]: [ANN] Emit Mapper
От: Holms США  
Дата: 18.11.09 22:14
Оценка:
Здравствуйте, koandrew, Вы писали:


K>Бегло просмотрел. Вывод — BLToolkit круче


А как с подержкой Silverlight-a в BLToolkit-e?
... << RSDN@Home 1.2.0 alpha 4 rev. 1253>>
The life is relative and reversible.
Re[2]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 18.11.09 22:16
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Бегло просмотрел. Вывод — BLToolkit круче


Только это разные вещи. Emit Mapper — это библиотека, которую можно использовать для разработки своего собственного BLToolkit с учетом своих собственных требований и пожеланий. Примеры меппинга для DbDataReader и DbCommand приведены исключительно для демонстрации возможностей.
лэт ми спик фром май харт
Re[3]: [ANN] Emit Mapper
От: Holms США  
Дата: 18.11.09 22:17
Оценка:
Здравствуйте, mrTwister, Вы писали:


T>Имхо, заставлять вешать атрибуты — это еще больший моветон. Это примерно как заставлять наследоваться от специального класса. Тем более, что ничто не мешает реализовать требуемую функциональность своими силами на основе Emit Mapper. Самый простой путь — это тупо отнаследоваться от DefaultMapConfig и переопределить логику игнора с учетом своих собственных требований и пожеланий (это могут быть не только атрибуты):


ага ясно, ну тогда хорошо.
еще-бы подержку Silverlight-а добавили и было бы всё пучком
... << RSDN@Home 1.2.0 alpha 4 rev. 1253>>
The life is relative and reversible.
Re[3]: [ANN] Emit Mapper
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 19.11.09 00:17
Оценка:
Здравствуйте, Holms, Вы писали:

H>А как с подержкой Silverlight-a в BLToolkit-e?


Всё будет
[КУ] оккупировала армия.
Re[4]: [ANN] Emit Mapper
От: Holms США  
Дата: 19.11.09 01:13
Оценка:
Здравствуйте, koandrew, Вы писали:


K>Всё будет

то что будет для SL + LINQ + code generation tool никто не сомневается, мне щас надо, поэтому остановился пока на SubSonic (осбенно мне нравится генериция ДБ обьектов из моих C# классов).
... << RSDN@Home 1.2.0 alpha 4 rev. 1253>>
The life is relative and reversible.
Re[5]: [ANN] Emit Mapper
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 19.11.09 01:17
Оценка:
Здравствуйте, Holms, Вы писали:

H>то что будет для SL + LINQ

Над этим работают
H>+ code generation tool
Вряд ли будет, ибо свой тул с таким функционалом пишется за полчаса-час.
[КУ] оккупировала армия.
Re[2]: [ANN] Emit Mapper
От: Andy77 Ниоткуда  
Дата: 19.11.09 02:05
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Бегло просмотрел. Вывод — BLToolkit круче


Круче, конечно. А как там реализовать похожую фичу?
Re[3]: [ANN] Emit Mapper
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 19.11.09 02:49
Оценка: +1
Здравствуйте, mrTwister, Вы писали:

T>Только это разные вещи. Emit Mapper — это библиотека, которую можно использовать для разработки своего собственного BLToolkit с учетом своих собственных требований и пожеланий. Примеры меппинга для DbDataReader и DbCommand приведены исключительно для демонстрации возможностей.


Вообще-то БЛТ в первую очередь маппер, а у же потом всё остальное. Вот автор увидит топик и расскажет подробнее
[КУ] оккупировала армия.
Re[4]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 19.11.09 06:48
Оценка: :)
Здравствуйте, 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;
}


Результаты:

Emit Mapper (simple): 130 milliseconds
BLToolkit (simple): 32287 milliseconds
лэт ми спик фром май харт
Re[2]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 21.12.09 14:01
Оценка:
Здравствуйте, Holms, Вы писали:


H>
H>var a = ObjectsMapperManager.DefaultInstance.GetMapper<B, A>(
H>        new DefaultMapConfig().IgnoreMembers<B, A>(new[]{"str1"})
H>    ).Map(new B());
H>


H>Кстати, под Silverlight работает? Если нет, опять большой минус.


Теперь работает

P.S.: Выражаю огромное спасибо Holms за участие в портировании библиотеки на Silverlight!
лэт ми спик фром май харт
Re: [ANN] Emit Mapper
От: Аноним  
Дата: 30.12.09 08:57
Оценка:
Здравствуйте, mrTwister

Я хотел бы использовать EmitMapper для клонирования объектов.

Имею следующий объект, с вложенной коллекцией OrgNodeCollection :
    [Serializable]
    [XmlRoot(ElementName = "object")]
    public class OrgNode
    {
        [XmlIgnore]
        public OrgNode ParentNode { get; set; }

        #region XmlAttributes

        [XmlAttribute("otype")]
        public string Type { get; set; }

        [XmlAttribute("id")]
        public string Id { get; set; }

        [XmlAttribute("prel")]
        public string ParentRelation { get; set; }

        [XmlAttribute("alias")]
        public string Alias { get; set; }

        #endregion

        #region XmlTags

        [XmlElement("description")]
        public string Description { get; set; }

        #endregion

        private OrgNodeCollection _children;

        public OrgNode()
        {
            Children = new OrgNodeCollection();
        }

        [XmlArray("children")]
        [XmlArrayItem("object")]
        public OrgNodeCollection Children
        {
            get { return _children; }
            set { _children = value; _children.Parent = this; }
        }
    }
    
    [Serializable]
    public class OrgNodeCollection : List<OrgNode>
    {
        private OrgNode _parent;

        public OrgNode Parent
        {
            get { return _parent; }
            set
            {
                _parent = value;
                foreach (var collection in this)
                {
                    collection.ParentNode = Parent;
                }
            }
        }

        public new void Add(OrgNode item)
        {
            base.Add(item);
            item.ParentNode = Parent;
        }
    }


Маппер использую вот так:

private static readonly Mapper<OrgNode, OrgNode> Mapper = ObjectsMapperManager.DefaultInstance.GetMapper<OrgNode, OrgNode>(new DefaultMapConfig().DeepMap<OrgNode>());

_savedObject = Mapper.Map<OrgNode, OrgNode>(node);


далее когда выполняю:

_savedObject.Children.Clear();


коллекция Children становится пустой и у _savedObject и у node. Соответственно коллекция Children одна та же.

Как заставить это работать?
Re[5]: [ANN] Emit Mapper
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.12.09 19:26
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Да и производительность у БЛТ маппера оставляет желать лучшего. На простеньком тесте (класс без вложеных объектов) БЛТ оказался в 250 раз медленнее. Вот код теста:


А ты не задумывался о том, что у BLT может быть ленивая генерация кода?
... << RSDN@Home 1.2.0 alpha 4 rev. 1324 on Windows 7 6.1.7600.0>>
AVK Blog
Re[2]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 30.12.09 19:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, mrTwister


А>Я хотел бы использовать EmitMapper для клонирования объектов.

А>Маппер использую вот так:

А>
А>private static readonly Mapper<OrgNode, OrgNode> Mapper = ObjectsMapperManager.DefaultInstance.GetMapper<OrgNode, OrgNode>(new DefaultMapConfig().DeepMap<OrgNode>());

А>_savedObject = Mapper.Map<OrgNode, OrgNode>(node);
А>


А>далее когда выполняю:


А>
А>_savedObject.Children.Clear();
А>


А>коллекция Children становится пустой и у _savedObject и у node. Соответственно коллекция Children одна та же.


А>Как заставить это работать?


Нужно создавать маппер следующим образом:

private static readonly Mapper<OrgNode, OrgNode> Mapper = 
    ObjectsMapperManager.DefaultInstance.GetMapper<OrgNode, OrgNode>(new DefaultMapConfig().DeepMap());
лэт ми спик фром май харт
Re[6]: [ANN] Emit Mapper
От: mrTwister Россия  
Дата: 30.12.09 19:44
Оценка:
Здравствуйте, 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;
}
лэт ми спик фром май харт
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.