Здравствуйте, WolfHound, Вы писали:
T>>>Задумывался. Именно по-этому в тесте есть строчка (выделено жирным): WH>Так очевидно что именно...
WH>d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);
WH>mapper.Map(s, d);
WH>BLT каждый раз создает новый объект. EM тупо копирует в один и тотже не напрягая GC.
Ясно. Что то подобное я и предполагал.
... << RSDN@Home 1.2.0 alpha 4 rev. 1324 on Windows 7 6.1.7600.0>>
Здравствуйте, WolfHound, Вы писали:
WH>Так очевидно что именно...
WH>d = BLToolkit.Mapping.Map.ObjectToObject<A2>(s);
WH>mapper.Map(s, d);
WH>BLT каждый раз создает новый объект. EM тупо копирует в один и тотже не напрягая GC.
Дак это проблемы BLT. Он другого интерфейса не предоставляет.
Плюс к этому BLT при конвертации value типов делает боксинг/анбоксинг. EM обходится без этого.
Здравствуйте, mrTwister, Вы писали:
T>Дак это проблемы BLT. Он другого интерфейса не предоставляет. T>Плюс к этому BLT при конвертации value типов делает боксинг/анбоксинг. EM обходится без этого.
Лично я вижу только одно объяснение этому: Данные сценарии за все время существования BLT ни кому ни разу не понадобились.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Там где можно дженерик методы можно было бы переписать следующим образом:
static class MapperImpl<TFrom,TTo>
{
public static ObjectsMapper<TFrom,TTo> Instance = new ObjectsMapper<TFrom, TTo>(
new ObjectsMapperManager().GetMapperImpl(
typeof(TFrom),
typeof(TTo),
DefaultMapConfig.Instance
)
);
}
public ObjectsMapper<TFrom, TTo> GetMapper<TFrom, TTo>()
{
return MapperImpl<TFrom,TTo>.Instance;
}
Тогда время на инициализацию и получение мапперов можно свести практически в абсолютный ноль.
Сравнительный тест с BLT конечно же слегка наивен. В тесте BLT тестируется не столько маппинг, сколько время доступа к мапперу. Впрочем, обо всём по порядку.
T>Имхо, заставлять вешать атрибуты — это еще больший моветон. Это примерно как заставлять наследоваться от специального класса. Тем более, что ничто не мешает реализовать требуемую функциональность своими силами на основе Emit Mapper.
Этот подход ведёт в никуда. Пользователям нужна готовая функциональность, а не потенциальная возможность. Это я как собаковод говорю. "ничто не мешает реализовать" в 99.99% случаев означает, что никто ничего реализовывать никогда и не будет. Более того, разработчик инструмента должен держать своё мнение о моветонах при себе. Учить пользователей жизни — это не его работа. Нормальное объяснение отсутсвия какой-либо функциональности в инструменте это: лень, нет времени, технические проблемы, отсутствие выгоды и т.п. "еще больший моветон" можно обсуждать у нас в Философии и желательно вне контекста конкретного инструмента.
T>Как раз как маппер, БЛТ довольно слабый (ценность БЛТ не в маппере). Он не поддерживает даже вложенные объекты, не конфигурируется и т.д. По крайней мере не справился даже с такой простой задачкой:
Как раз как маппер, в реальных сценариях BLT даст фору кому угодно. "Даже вложенные объекты" в BLT не поддерживаются по-умолчанию. Кстати, они не поддерживаются по-умолчанию практически нигде, т.к. это вызывает больше проблем, чем бенефитов. Научить BLT справляться с поставленной задачкой можно, например, следующим образом:
[MapField("str2", "i.str2")]public class Destination
{
public class Int
{
public string str2;
}
public string str1;
public Int i = new Int();
}
[MapField("str2", "i.str2")]public class Source
{
public class Int
{
public string str2 = "B1::Int::str2";
}
public string str1 = "B1::str1";
public Int i = new Int();
}
T>Да и производительность у БЛТ маппера оставляет желать лучшего. На простеньком тесте (класс без вложеных объектов) БЛТ оказался в 250 раз медленнее. Вот код теста:
Думаю, любому взрослому и умному человеку, заинтересованному в конечном результате, обязательно захотелось бы найти объснению такому чудовищному отставанию в производительности и разобраться что же происходит на самом деле, а не отмазываться фразами вроде "Дак это проблемы BLT. Он другого интерфейса не предоставляет.". Тем более, что и интерфейс такой у BLT есть и у EM есть интерфейс, который поставил бы библиотеки в одинаковые условия. И тогда 250 раз мгновенно уменьшились бы на 125. Хотя проблема, конечно, не в этом.
Разница в производительности объясняется прежде всего тем, что в тесте EM тестируется только маппер, а в тесте BLT тестируется не столько маппер, сколько способ его получения. API для получения маппера как это происходит в сценарии в BLT попросту отсутствует. Не то что бы это было трудно сделать, но просто за 8 лет существования библиотеки это пока никому не было нужно. Сценариев где нужен маппинг одного объектв в другой не так много, высокопроизводительных сценариев ещё меньше, а когда они реально возникают, то написать код вручную, особенно сегодня при наличии инициализаторов в C# не представляет особой сложности.
В общем, BLT под такие сценарии никогда не оптимизировался. Другое дело вот такие сценарии:
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_List(int mappingsCount)
{
var list = new List<B2>();
for (var i = 0; i < mappingsCount; i++)
list.Add(new B2());
var sw = new Stopwatch();
sw.Start();
var dest = Map.ListToList<A2>(list);
sw.Stop();
return sw.ElapsedMilliseconds;
}
static long EmitMapper_List(int mappingsCount)
{
var list = new List<B2>();
for (var i = 0; i < mappingsCount; i++)
list.Add(new B2());
var sw = new Stopwatch();
sw.Start();
var mapper = ObjectsMapperManager.DefaultInstance.GetMapper<B2, A2>();
var dest = new List<A2>();
foreach (var item in list)
dest.Add(mapper.Map(item));
sw.Stop();
return sw.ElapsedMilliseconds;
}
Здесь мы уже имеем разницу не в 250 раз, а около двух, хотя и не в пользу BLT. Оставшаяся разница объясняется тем, что BLT делает больше проверок в рантайм. Например, если изменить приведённый выше код следующим образом, то EM упадёт:
public class B2
{
...
public decimal? n5 = null;
....
}
Некоторые из этих проверок можно сократить только генерацией кода под каждый конкретный вариант использования, что практически не имеет смысла если не кешировать каким-то образом сам вариант использования или явно не напрягать пользователя, что бы он его как-то идентифицировал. В приведённых выше тестах EM именно этим и занимается. Это хорошо работает с объектами, но не работает с источниками данных, структура которых становится известной только в момент выполнения. К таким источникам относятся, например, базы данных. Кстати, давайте посмотрим что у нас с базами данных:
static long BLToolkit_DB(int mappingsCount)
{
DbManager.AddConnectionString("data source=.;initial catalog=Northwind;integrated security=SSPI;");
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < mappingsCount; i++)
{
using (var db = new DbManager())
{
var list = db
.SetCommand("SELECT * FROM Customers")
.ExecuteList<Customers>();
}
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
static long EmitMapper_DB(int mappingsCount)
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < mappingsCount; i++)
{
using(var con = new SqlConnection("data source=.;initial catalog=Northwind;integrated security=SSPI;"))
using(var cmd = con.CreateCommand())
{
con.Open();
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT * FROM Customers";
using (var reader = cmd.ExecuteReader())
{
var list = reader.ToObjects<Customers>(null).ToList();
}
}
}
sw.Stop();
return sw.ElapsedMilliseconds;
}
В этом примере EM уже начинает отставать. Скорее всего reader.ToObjects, взятый из примеров библиотеки не очень хорош. При этом он не очень хорош будучи написанным самим автором библиотеки, а что будет написано, если будет, пользователями, плохо знакомыми как с самой библиотекой, так и с базами данных?
В общем, библиотеку нужно допиливать под реалии. С синтетическими тестами она уже справляется хорошо, т.е. задел есть и надо признать задел неплохой.
Ну и в заключении, вот такие примеры в качестве сценарии использования библиотеки из документации лучше убрать:
public DTOCustomer GetCustomer(Guid customerId)
{
using (var dc = new DataContext())
{
var customer = dc.Customers.Where(c => c.CustomerID == customerId).Single();
return ObjectsMapperManager.DefaultInstance.GetMapper<Customer, DTOCustomer>().Map(customer);
}
}
И в самом самом заключении, ObjectsMapperManager — это немного не по-английски.
Если нам не помогут, то мы тоже никого не пощадим.
пост не в тему, но
последняя версия BL из svn не компилится, можете поправить
вот пара ошибок
EditableObjects\NotifyCollectionChangeTest.cs(497,48): error CS0433: The type 'System.Collections.Specialized.NotifyCollectionChangedEventArgs' exists in both 'f:\svn\bl-toolkit\Source\bin\Release\BLToolkit.3.dll' and 'c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll'
EditableObjects\NotifyCollectionChangeTest.cs(62,58): error CS0433: The type 'System.Collections.Specialized.NotifyCollectionChangedEventArgs' exists in both 'f:\svn\bl-toolkit\Source\bin\Release\BLToolkit.3.dll' and 'c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll'
EditableObjects\NotifyCollectionChangeTest.cs(446,52): error CS0433: The type 'System.Collections.Specialized.NotifyCollectionChangedEventArgs' exists in both 'f:\svn\bl-toolkit\Source\bin\Release\BLToolkit.3.dll' and 'c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll'
Done Building Project "F:\svn\bl-toolkit\UnitTests\CS\UnitTests.CS.csproj" (default targets) -- FAILED.
Project "F:\svn\bl-toolkit\BLToolkit.2008.sln" (1) is building "F:\svn\bl-toolkit\UnitTests\Linq\UnitTests.Linq.csproj" (13) on node 0 (default targets).
Processing 0 EDMX files.
Finished processing 0 EDMX files.
ConvertTest.cs(7,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
CompileTest.cs(7,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
MathFunctions.cs(3,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
Exceptions\Inheritance.cs(6,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
Model\NorthwindDB.cs(4,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
Exceptions\Mapping.cs(5,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
Functions.cs(7,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
DateTimeFunctions.cs(6,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
StringFunctions.cs(8,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
TestDbManager.cs(4,22): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
WhereTest.cs(11,23): error CS0234: The type or namespace name 'Linq' does not exist in the namespace 'BLToolkit.Data' (are you missing an assembly reference?)
Model\NorthwindDB.cs(14,10): error CS0246: The type or namespace name 'Table' could not be found (are you missing a using directive or an assembly reference?)
Model\NorthwindDB.cs(15,10): error CS0246: The type or namespace name 'Table' could not be found (are you missing a using directive or an assembly reference?)
Model\NorthwindDB.cs(16,10): error CS0246: The type or namespace name 'Table' could not be found (are you missing a using directive or an assembly reference?)
Кстати, какие планы насчет Silverlight-а. Будет поддержка?
Спасибо
Здравствуйте, Holms, Вы писали:
H>пост не в тему, но H>последняя версия BL из svn не компилится, можете поправить H>вот пара ошибок
Только что пересобрал в обоих фреймворках. Компилируется нормально. Может какие-то проблемы с локальной версией?
H>Кстати, какие планы насчет Silverlight-а. Будет поддержка?
Сделаем. Технических проблем пока вроде не видно.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Только что пересобрал в обоих фреймворках. Компилируется нормально. Может какие-то проблемы с локальной версией?
а какие проблемы могут быть? я взял то что в SVN-е потом запустил
Здравствуйте, Holms, Вы писали:
IT>>Только что пересобрал в обоих фреймворках. Компилируется нормально. Может какие-то проблемы с локальной версией? H>а какие проблемы могут быть? я взял то что в SVN-е потом запустил H>
IT>Твой вариант я тоже только что проверил, всё работает.
я беру отсюда http://bl-toolkit.googlecode.com/svn/trunk
мне выдаёт Revision 864, и файла BLToolkit.3.csproj в руте нету.
что-то здесь не то, и вот что конкретно
если брать откуда я беру то получаем всё что там е тебя есть, и файл BLToolkit.2008.sln не содержит линк на Source/BLToolkit.3.csproj
после запуска Source/Compile3.bat то и BLToolkit.2008.sln собралось без проблем.
IT>Что нужнее, DML или SL?
что скрывается под DML?
Здравствуйте, IT, Вы писали:
IT>Совсем не плохо.
Спасибо!
IT>Там где можно дженерик методы можно было бы переписать следующим образом: IT>
IT>static class MapperImpl<TFrom,TTo>
IT>{
IT> public static ObjectsMapper<TFrom,TTo> Instance = new ObjectsMapper<TFrom, TTo>(
IT> new ObjectsMapperManager().GetMapperImpl(
IT> typeof(TFrom),
IT> typeof(TTo),
IT> DefaultMapConfig.Instance
IT> )
IT> );
IT>}
IT>public ObjectsMapper<TFrom, TTo> GetMapper<TFrom, TTo>()
IT>{
IT> return MapperImpl<TFrom,TTo>.Instance;
IT>}
IT>
IT>Тогда время на инициализацию и получение мапперов можно свести практически в абсолютный ноль.
Вообще, идея очень интересная, но к сожалению в случае с EM неприменима, так как для одних и тех же типов могут существовать разные конфигурации мэпперов.
IT>Этот подход ведёт в никуда. Пользователям нужна готовая функциональность, а не потенциальная возможность. Это я как собаковод говорю. "ничто не мешает реализовать" в 99.99% случаев означает, что никто ничего реализовывать никогда и не будет. Более того, разработчик инструмента должен держать своё мнение о моветонах при себе. Учить пользователей жизни — это не его работа. Нормальное объяснение отсутсвия какой-либо функциональности в инструменте это: лень, нет времени, технические проблемы, отсутствие выгоды и т.п.
Вообще, вопрос выбора между "рыбой и удочкой" непростой и не содержит простого однозначного ответа. Всего при реализации некоторых прикладных библиотек мне видятся следующие стратегии:
1) Стратегия "Рыба". Предугадать возможные варианты использования и реализовать под них готовую функциональность. (это как раз то, о чем ты говоришь)
2) Стратегия "Удочка". Предоставив пользователю интерфейс с помощью которого он может самостоятельно добиться желаемого результата. Тем самым автоматически покрывается большинство вариантов использования и даже те из них, о существовании которых автор библиотеки даже не подозревает.
Каждая из стратегий имеет свои достоинства и недостатки, соответственно исходить надо из задачи. Задача Object2Object mapping — это задача с очень смутными и неопределенными вариантами использования из-за того, что их очень много. Ведь сопоставление полей объектов можно выполнять кучей разных способов: можно основываться на именах и при этом либо учитывать регистр, или нет, учитывать префиксы типа "m_", "_" или нет, можно основываться на атрибутах (но этот метод не всегда применим и весьма негибок), можно основываться на специальных XML схемах — на чем угодно, на что может хватить фантазии разработчика (я уже не говорю о более сложных задачах типа преобразования типов, коллекций, дженериков, пост/пре обработки и т.д.). Трезво оценивая свои возможности я понял, что не смогу в приемлимые сроки спроектировать и реализовать интерфейс таким образом, чтобы он покрыл все эти варианты использования, а также те, о которых я ещё не подумал. Вместо этого появилась идея разработать библиотеку, которая с минимальными усилиями позволяет разработчику самому реализовать те варианты ипользования, которые ему нужны, причем именно так, как он себе и представляет идеальным образом. Обрати внимание, что когда был надан вопрос на счет атрибутов мне было не лень продемонстрировать всего несколько строчек кода, реализующие мэппинг через атрибуты. Собственно для этого библиотека и создавалась.
IT>Как раз как маппер, в реальных сценариях BLT даст фору кому угодно.
Смотря на каких сценариях. Если это сценарии связанные с БД, то скорее всего да, ведь он именно на эти сценарии и заточен. Если же рассматривать сценарии Object2Object, то уже вряд ли, так как БЛТ сильно уступает конкурентам по функционалу и количеству покрываемых вариантов использования.
IT>"Даже вложенные объекты" в BLT не поддерживаются по-умолчанию. Кстати, они не поддерживаются по-умолчанию практически нигде,
Ну почему же, AutoMapper поддерживает, и многие другие Object2Object mapping библиотеки поддерживают. Я бы даже сказал, что большинство из них.
IT>т.к. это вызывает больше проблем, чем бенефитов.
Все проблемы решаемы.
IT>Научить BLT справляться с поставленной задачкой можно, например, следующим образом:
IT>
IT>[MapField("str2", "i.str2")]
IT>public class Destination
IT>{
IT> public class Int
IT> {
IT> public string str2;
IT> }
IT> public string str1;
IT> public Int i = new Int();
IT>}
IT>[MapField("str2", "i.str2")]
IT>public class Source
IT>{
IT> public class Int
IT> {
IT> public string str2 = "B1::Int::str2";
IT> }
IT> public string str1 = "B1::str1";
IT> public Int i = new Int();
IT>}
IT>
Ну, это уже "закат солнца вручную". Если уж нет автоматики, не проще ли тогда вообще написать:
Destination.i.str2 = Source.i.str2;
Тут по крайней мере и интеллисенс есть и компилятор ошибки проверит.
IT>Думаю, любому взрослому и умному человеку, заинтересованному в конечном результате, обязательно захотелось бы найти объснению такому чудовищному отставанию в производительности и разобраться что же происходит на самом деле,
Ну это очевидно, я же выше по теме написал из-за чего разница в производительности.
IT>а не отмазываться фразами вроде "Дак это проблемы BLT. Он другого интерфейса не предоставляет.". Тем более, что и интерфейс такой у BLT есть
Как это есть? Ты же сам пишешь, что:
API для получения мэппера как это происходит в сценарии в BLT попросту отсутствует.
IT>и у EM есть интерфейс, который поставил бы библиотеки в одинаковые условия. И тогда 250 раз мгновенно уменьшились бы на 125. Хотя проблема, конечно, не в этом.
А зачем их ставить в одинаковые условия? Это примерно как при сравнении производительности бейсика и С++ код на С++ интерпретировать дабы поставить их в одинаковые условия и тем самым доказать, что бейсик не медленее С++.
EmitMapper проектировался в первую очередь как Object2Object mapper. В этом случае схемы данных источников и получателей известны заранее и нет проблемы с тем, чтобы создать конфигурацию мэппера под конкретные схемы данных заранее (например при старте программы) и затем её только использовать. Посмотри выше по теме здесь
- человек именно так и делает.
IT>Сценариев где нужен маппинг одного объектв в другой не так много, высокопроизводительных сценариев ещё меньше, а когда они реально возникают, то написать код вручную, особенно сегодня при наличии инициализаторов в C# не представляет особой сложности.
Написать код не проблема, проблема его поддерживать. Как показывает практика, достаточно большое количество багов возникает из-за того, что при добавлении нового поля забываем прописать копирование этого поля в одном из существующих ручных мэпперов.
IT>В общем, BLT под такие сценарии никогда не оптимизировался. Другое дело вот такие сценарии:
IT>
IT>...
IT>
IT>Здесь мы уже имеем разницу не в 250 раз, а около двух, хотя и не в пользу BLT.
У меня получается разница в 4-5 раз. Ну да неважно, это уже более-менее сравнимо.
IT>Оставшаяся разница объясняется тем, что BLT делает больше проверок в рантайм. Например, если изменить приведённый выше код следующим образом, то EM упадёт:
IT>
IT>public class B2
IT>{
IT> ...
IT> public decimal? n5 = null;
IT> ....
IT>}
IT>
И это очень зря, что БЛТ проглотил данную явно ошибочную ситуацию. Что он поставит вместо null? 0? А почему не -1 или не 42?
EM поддерживает NullSubstitution и с помощью следующей конфигурации можно создать мэппер, который вместо null будет писать 42:
var mapper = ObjectsMapperManager.DefaultInstance.GetMapper<B2, A2>(
new DefaultMapConfig().NullSubstitution<decimal?,int>( state => 42 )
);
Этот мэппер уже не падает.
IT>Некоторые из этих проверок можно сократить только генерацией кода под каждый конкретный вариант использования, что практически не имеет смысла если не кешировать каким-то образом сам вариант использования или явно не напрягать пользователя, что бы он его как-то идентифицировал. В приведённых выше тестах EM именно этим и занимается.
К сожалению, без этого нелься сделать сколько-нибудь гибкий мэппер.
IT>Это хорошо работает с объектами, но не работает с источниками данных, структура которых становится известной только в момент выполнения. К таким источникам относятся, например, базы данных.
Согласен.
IT>Кстати, давайте посмотрим что у нас с базами данных: IT>
IT>...
IT>
IT>В этом примере EM уже начинает отставать.
Верно, но после маленькой оптимизации (заменил DbDataReader[String] на DbDataReader[Int]) EM уже начал обгонять BLT.
IT>Скорее всего reader.ToObjects, взятый из примеров библиотеки не очень хорош.
Во-первых, EM — это не про базы данных. Конфигурация мэппера для дадатидера была показана для примера. Во-вторых, отставание было на считанные проценты на синтетическом примере, при котором вызов "SqlCommand.ExecuteReader" по результатам профилирования составляет всего 4% от общего времени работы программы. В-третьих это уже поправлено
IT>При этом он не очень хорош будучи написанным самим автором библиотеки, а что будет написано, если будет, пользователями, плохо знакомыми как с самой библиотекой, так и с базами данных?
Ничего страшного не случилось бы. Если для кого-то несколько процентов в абсолютной разнице в производительности между DbDataReader[String] и DbDataReader[Int] очень существенны, то, возможно, вместо базы данных следовало бы использовать что-то другое? (потому как судя по всему СУБД простаивает без дела).
IT>Ну и в заключении, вот такие примеры в качестве сценарии использования библиотеки из документации лучше убрать:
IT>
IT>public DTOCustomer GetCustomer(Guid customerId)
IT>{
IT> using (var dc = new DataContext())
IT> {
IT> var customer = dc.Customers.Where(c => c.CustomerID == customerId).Single();
IT> return ObjectsMapperManager.DefaultInstance.GetMapper<Customer, DTOCustomer>().Map(customer);
IT> }
IT>}
IT>
А что с ним не так?
IT>И в самом самом заключении, ObjectsMapperManager — это немного не по-английски.
Ок
Здравствуйте, mrTwister, Вы писали:
T>1) Стратегия "Рыба". Предугадать возможные варианты использования и реализовать под них готовую функциональность. (это как раз то, о чем ты говоришь) T>2) Стратегия "Удочка". Предоставив пользователю интерфейс с помощью которого он может самостоятельно добиться желаемого результата. Тем самым автоматически покрывается большинство вариантов использования и даже те из них, о существовании которых автор библиотеки даже не подозревает.
Правильная стратегия — рыба для публично доступного ядра и удочка для набора функционала вокруг. Именно по такой схеме построен BLT.
... << RSDN@Home 1.2.0 alpha 4 rev. 1331 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Правильная стратегия — рыба для публично доступного ядра и удочка для набора функционала вокруг. Именно по такой схеме построен BLT.
Вопрос только в объеме рыбы и простоте и доступности удочек.
Здравствуйте, AndrewVK, Вы писали:
AVK>А это вовсе не вопрос, потому что проблемы с конкретной удочкой вполне решаемы написанием собственной удочки в крайнем случае.
Прекрасно. Сколько надо написать кода для маппинга вложенных структур (в том числе рекурсивных)?