Я создаю простой тип mapper, похожий на AutoMapper, но с более динамичным поведением. Вызывающий абонент может принять решение об отфильтровывании RecordStatus == RecordStatus.Deleted
записей при сопоставлении с файловыми моделями сущностей.Ограничение и дисперсия общего типа
Аннотация картостроители:
public interface IMapper<in TIn, out TOut>
{
TOut Map(TIn input);
}
public interface IRecordStatusFilterable
{
string RecordStatus { get; }
}
public abstract class RecordStatusFilterableMapperBase<TIn, TOut> : IMapper<TIn, TOut>
{
private readonly bool _filterDeletedRecords;
protected RecordStatusFilterableMapperBase(bool filterDeletedRecords)
{
_filterDeletedRecords = filterDeletedRecords;
}
protected bool FilterDeletedRecords
{
get { return _filterDeletedRecords; }
}
public abstract TOut Map(TIn input);
}
public class MultiLookupValuesMapper : RecordStatusFilterableMapperBase<IEnumerable<Lookup>, string>
{
private static readonly Func<Lookup, bool> _predicate =
filterable => filterable.RecordStatus == RecordStatus.Active;
protected MultiLookupValuesMapper(bool filterDeletedRecords) : base(filterDeletedRecords)
{
}
public override string Map(IEnumerable<Lookup> input)
{
var inputList = input as IList<Lookup> ?? input.ToList();
if (!inputList.Any())
{
return string.Empty;
}
if (FilterDeletedRecords)
{
inputList = (IList<Lookup>)inputList.Where(_predicate);
}
return string.Join(", ", inputList.Select(l => l.Value));
}
}
Бетон Картостроители:
public class FooMapper<TRecordStatusFilterable> : RecordStatusFilterableMapperBase<Foo, FooViewModel>
where TRecordStatusFilterable : class, IRecordStatusFilterable
{
private readonly IMapper<IEnumerable<TRecordStatusFilterable>, string> _multiLookupValueMapper;
public FooMapper(IMapper<IEnumerable<TRecordStatusFilterable>, string> multiLookupValueMapper,
bool filterDeletedRecords) : base(filterDeletedRecords)
{
_multiLookupValueMapper = multiLookupValueMapper;
}
public override FooViewModel Map(Foo input)
{
return new FooViewModel
{
// Error here
BarLookupValues = _multiLookupValueMapper.Map(input.Lookups)
};
}
}
Entity Framework модели:
public class Foo
{
public ICollection<Lookup> Lookups { get; set; }
}
public class Lookup : IRecordStatusFilterable
{
public string Value { get; set; }
public string RecordStatus { get; set; }
}
ViewModels:
public class FooViewModel
{
// ICollection<Lookup> => string
public string BarLookupValues { get; set; }
}
я получил ошибку компиляции:
Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<Lookup>' to 'System.Collections.Generic.IEnumerable<TRecordStatusFilterable>'
Но мой Lookup
класс делает выполнить родовое ограничение параметра типа, как он реализует IRecordStatusFilterable
. Может кто-нибудь пролить некоторый свет на это?
'Lookup' - это класс, который удовлетворяет ограничению, но не является типом' TRecordStatusFilterable', который является держателем места для любого конкретного типа. Нет никакой гарантии, что 'Lookup' совместим с общим типом аргумента при создании экземпляра. –
Могу я спросить, почему? '_multiLookupValueMapper' имеет тип' IMapper, string> 'и я вызывал' _multiLookupValueMapper.Map' с 'ICollection '. Почему это невозможно? –
rexcfnghk