Что касается вашего абстрактного класса, рассмотрите возможность избавиться от него и заменить его на метод расширения.Это позволит вам использовать функцию MapAll
независимо от того, реализуете ли вы интерфейс или используете какую-то цепочку наследования.
public static class MapperExtensions
{
public static IEnumerable<TOutput> MapAll<TInput, TOutput>
(this IMapper<TInput, TOutput> mapper, IEnumerable<TInput> input)
{
return input.Select(x => mapper.Map(x));
}
}
Теперь это будет проще при попытке решить вашу проблему, указанную выше, потому что выбольше не нужно наследовать от базового класса, теперь вы можете реализовать интерфейс отображения для типов, которые вы хотите отобразить.
public class BillHistoryMapper :
IMapper<Invoice, BillHistory>, IMapper<Payment, BillHistory>
{
public BillHistory Map<Invoice>(Invoice obj) {}
public BillHistory Map<Payment>(Payment obj) {}
}
Также рассмотрите возможность изменения общих параметров IMapper
, чтобы они были наоборот (Iвзял на себя смелость в предыдущих примерах):
public interface IMapper<in TInput, out TOutput>
{
TOutput Map(TInput input);
}
Причина этого в том, что он напрямую отображается на делегат System.Converter<T>
, и вы можете сделать что-то вроде:
IMapper<ObjectA, ObjectB> myAToBMapper = new MyAToBMapper();
ObjectA[] aArray = { new ObjectA(), new ObjectA() };
ObjectB[] bArray = Array.ConvertAll<ObjectA, ObjectB>(aArray, myAToBMapper.Map);
List<ObjectA> aList = new List<ObjectA> { new ObjectA(), new ObjectA() };
List<ObjectB> bList = aList.ConvertAll<ObjectB>(myAToBMapper.Map);
// Or
var aToBConverter = new Converter<ObjectA, ObjectB>(myAToBMapper.Map);
bArray = Array.ConvertAll(aArray, aToBConverter);
bList = aList.ConvertAll(aToBConverter);
AutoMapper также было предложено, что сделает вашу жизнь проще.Однако, если вы хотите сохранить абстракцию сопоставления и иметь независимый от кода код для вашей стратегии сопоставления, очень легко использовать вышеуказанный интерфейс для внедрения оболочки вокруг AutoMapper.Это также будет означать, что вы можете продолжать использовать метод расширения MapAll
, описанный выше.
public class AutoMapperWrapper<in TInput, out TOutput> : IMapper<TInput, TOutput>
{
public TOutput Map(TInput input)
{
return Mapper.Map<TOutput>(input);
}
}
Последнее слово
Также имейте в виду, что вы не всегда собираетесьчтобы убедиться, что ваша стратегия сопоставления будет работать по всем направлениям, не пытайтесь бороться с вашим доменом и заставить его соответствовать вашей стратегии сопоставления.Один конкретный пример - вам может понадобиться отобразить два входных элемента в один.Очевидно, вы можете сделать это в соответствии со своей стратегией, но вы можете обнаружить, что это становится грязным.В этом конкретном примере рассмотрим это слияние.