EmitMapper - 从抽象模型对象到抽象DTO的通用映射

时间:2014-05-31 22:52:03

标签: c# valueinjecter emitmapper

我需要一些帮助,从ValueInjecter转换为EmitMapper(出于性能原因,我已经决定了这一点)。我的用例是最常见的用例之一:根据一些规则将Model对象映射到DTO。

其中一条规则是:如果属性类型是DomainObject的子类,则应将其映射到其对应的DTO 。具体类型可以,但我也希望它与抽象类型一起使用。问题是我不知道如何以动态的方式告诉EmitMapper应该使用哪个DTO。

在ValueInjecter代码中:

public bool IsDomainObjectAndTargetIsDto(ConventionInfo it) 
{
    return it.SourceProp.Value.IsNotNull()
        && typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
        && it.TargetProp.Type.Name.EndsWith("DTO");
}

由于我的所有DTO都实现了DTO<>接口,我认为我可以使用EmitMapper的DefaultMapConfig.ConvertGeneric方法,但我无法弄清楚如何。

为了完整起见,我包含了我当前(不工作)的代码:

public class ModelToDtoConventions() 
{
    public IMappingConfigurator GetConfig() 
    {
        return new DefaultMapConfig()
            .ConvertUsing<IdentificableObject, int>(o => o.Id)
            .ConvertGeneric(
                typeof (DomainObject), 
                typeof (DTO<>),
                new DefaultCustomConverterProvider(
                    typeof (DomainObjectToDtoConverter<>)
                )
            );
    }
}

public class DomainObjectToDtoConverter<TDomainObject>
{
    public DTO<TDomainObject> Convert(TDomainObject from, object state)
    {
        return (DTO<TDomainObject>)this.CreateDtoFor(@from);
    }

    private object CreateDtoFor(object modelObject)
    {
        var modelType = modelObject.GetType();
        var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);

        var dtoType = dtoInterface
            .GetConcreteSubtypes()
            .Single();

        return Activator.CreateInstance(dtoType);
    }
}

当我尝试在测试中使用此映射时,我得到以下异常

'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
    at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
    at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
    at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
    at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
    at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
    at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
    at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
    at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs  56  

编辑:这是我要映射的对象示例。

//Domain objects
public class Game
{
    public IEnumerable<Map> Maps { get; set; }
    public Map MostPlayedMap { get; set; }

    public Game()
    {
        this.Maps = new List<Map>();
    }
}

public abstract class Map : DomainObject
{
    public string Name { get; set; }
}

public class BombDefuseMap : Map
{
    public Player BombHolder { get; set; }
}

public class HostageRescueMap : Map
{
    public int QuantityOfHostages { get; set; }
}

//DTOs
public class GameDTO : DTOWithId<Game>
{
    public List<MapDTO> Maps { get; set; }
    public MapDTO MostPlayedMap { get; set; }
}

public abstract class MapDTO
{
    public string Name { get; set; }
}

public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
    public int BombHolder { get; set; }
}

public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
    public int QuantityOfHostages { get; set; }
}

1 个答案:

答案 0 :(得分:0)

如果您关注性能,请查看此页面: http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection

这是一种表现更好的注射,但你没有在匹配算法中获得价值, 大多数时候你根本不需要它