【问题标题】:C# covariant/contravariant types utilizing generics with DictionaryC#协变/逆变类型利用泛型和字典
【发布时间】:2020-01-30 08:05:55
【问题描述】:

我需要帮助解决我的代码中的协变情况。

让我用例子来说明情况:

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
            }
        }
    }
}

很快,我需要不同类型映射器的字典,并在通用代码中使用它们的 Execute 方法来处理工作流。

您能否指导我编写更好的代码或修复现有解决方案?有可能吗?

或者我必须在这里忘记泛型并在 Map 方法中使用 BaseClasses 并将它们转换为我需要的类型。

类似的东西

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

谢谢

【问题讨论】:

  • 你对泛型和接口的使用对我来说看起来很教科书。你为什么不满意?
  • 问题是,我不能将 IEntityMapper 的映射器转换为 var target = (IEntityMappermapper).Map(entity);。我需要转换它,因为我需要通用方法 Map 来执行实体映射。是不是更清楚了?
  • 实现IEntityMapper&lt;BaseSource,BaseTarget&gt; 的类承诺将继承自BaseSource 的任何类型的TSource 作为输入。但是GoodsEntityMapper 和OrderEntityMapper 都做不到。

标签: c# .net generics covariance


【解决方案1】:

您可以将BaseEntityMap&lt;TSource, TTarget&gt; 类中的通用约束应用于BaseSource 和BaseTarget 类(或在IEntityMapper&lt;in TSource, out TTarget&gt; 接口中应用约束并摆脱基本抽象类)

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

然后使用Func&lt;BaseSource, BaseTarget&gt; 委托声明如下映射器字典。应该没问题,因为您已经限制了 BaseEntityMap&lt;TSource, TTarget&gt; 和 Func&lt;in T, out TResult&gt; 声明支持输入参数的逆变和结果的协方差

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)
{
    var target = mapper(entity);
    //.... code continues
}

【讨论】:

  • @Glock 对您有帮助吗?您需要更多细节或解释吗?
  • 你好,是的,它有帮助。谢谢,我不考虑将其包装在委托中 :-) 谢谢
猜你喜欢
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2011-12-27
  • 1970-01-01
相关资源
最近更新 更多