C# ковариантные / контравариантные типы, использующие дженерики со словарем - PullRequest
0 голосов
/ 30 января 2020

мне нужно помочь с решением ковариантной ситуации в моем коде.

Позвольте мне показать ситуацию на примере:

abstract class BaseSource { }
abstract class BaseTarget { }

class SourceEntityA : BaseSource { }
class TargetEntityB : BaseTarget { }

interface IEntityMapper { }
interface IEntityMapper<in TSource, out TTarget>: IEntityMapper
{
    TTarget Map(TSource entity);
}


abstract class BaseEntityMap<TSource, TTarget> : IEntityMapper<TSource, TTarget>, IEntityMapper
{
    public abstract TTarget Map(TSource entity);
}

class OrderEntityMapper : BaseEntityMap<SourceEntityA, TargetEntityB>
{
    public override TargetEntityB Map(SourceEntityA entity)
    {
        //do some map stuff
        return null;
    }
}

class GoodsEntityMapper : BaseEntityMap<SourceEntityC, TargetEntityD>
{
    public override TargetEntityD Map(SourceEntityC entity)
    {
        //do some map stuff
        return null;
    }
}

class Workflow
{
    IDictionary<Type, IEntityMapper> MappersMap = new Dictionary<Type, IEntityMapper>();
    public MappingArchestrator()
    {
        MappersMap.Add(typeof(SourceEntityA), new OrderEntityMapper());
        MappersMap.Add(typeof(SourceEntityC), new GoodsEntityMapper());
        //....more mappers
    }
    private IEnumerable<BaseSource> GetSourceEntities()
    {

        //return source data
        return null;
    }
    public void Execute()
    {
        foreach (var m in MappersMap.Keys)
        {
            var mapper = MappersMap[m];

            var entities = GetSourceEntities();

            foreach (var entity in entities)
            {
                //Need to handle this situations with correct covariations.
                var target = (IEntityMapper<BaseSource, BaseTarget>mapper).Map(entity);
                //.... code continues
            }
        }
    }
}

В скором времени мне нужен словарь различных типов картографов и использовать их Выполните метод в общем коде для обработки рабочего процесса.

Не могли бы вы привести меня к лучшему коду или исправить существующее решение? Это вообще возможно?

Или я должен здесь забыть обобщения и использовать BaseClasses в методе Map и привести их к типу того, что мне нужно.

Что-то вроде этого

abstract class BaseEntityMap : IEntityMapper
{
    public abstract BaseTarget Map(BaseSource entity);
}

Спасибо

1 Ответ

1 голос
/ 30 января 2020

Вы можете применить родовые c ограничения в BaseEntityMap<TSource, TTarget> классе к вашим BaseSource и BaseTarget классам (или применить ограничения в IEntityMapper<in TSource, out TTarget> интерфейсе и избавиться от базового абстрактного класса)

abstract class BaseEntityMap<TSource, TTarget> : IEntityMapper<TSource, TTarget>
    where TSource : BaseSource
    where TTarget : BaseTarget
{
    public abstract TTarget Map(TSource entity);
}

Затем объявите словарь картографов, как показано ниже, используя Func<BaseSource, BaseTarget> делегат. Все должно быть в порядке, поскольку вы ограничили объявление BaseEntityMap<TSource, TTarget> и Func<in T, out TResult>, поддерживающее контравариацию для входного параметра и ковариацию для результата

IDictionary<Type, Func<BaseSource, BaseTarget>> MappersMap = new Dictionary<Type, Func<BaseSource, BaseTarget>>();

public Workflow()
{
    var orderMapper = new OrderEntityMapper();
    MappersMap.Add(typeof(SourceEntityA), source => orderMapper.Map((SourceEntityA)source));
    var goodsMapper = new GoodsEntityMapper();
    MappersMap.Add(typeof(SourceEntityC), source => goodsMapper.Map((SourceEntityC)source));
    //....more mappers
}

и пример выполнения

foreach (var entity in entities)
{
    //Need to handle this situations with correct covariations.
    var target = mapper(entity);
    //.... code continues
}
...