Automapper:绑定一个具体的class"from"多个接口

Automapper: binding a concrete class "from" multiple interface

我正在尝试使用 c# 和自动映射器映射 class (TrackingKeyStatic)。 TrackingKeyStatic 具有接口 IBatchProcessing 继承自具有接口 ITrackingKey 的 Trackingkey。 所以根据定义,TrackingKeyStatic 是 IBatchProcessing 和 ITrackingKey。

Automapper 仅使用一个接口即可正常工作 (IBatchProcessing) 但不能 mapped/be 检测接口 ITrackingKey

我创建了一个 fiddle 来演示 https://dotnetfiddle.net/TO21PI

所以问题是如何将具有两个接口的源映射到一个 croncrete 类型?

这是我为这个问题写的单元测试

using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Whosebug
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestWithItrackingAsSource_NOTWORKING()
        {
            var config = new MapperConfiguration(cfg => {
                cfg.CreateMap<ITrackingKey, MyEntitiesDbFirstModel>()
                    .ForMember(d => d.TrackingKey, o => o.MapFrom(s => s.NewTrackingKey));
                cfg.CreateMap<IBatchProcessing, MyEntitiesDbFirstModel>()
                    .ForMember(d => d.Skip, o => o.MapFrom(s => s.Skip))
                    .ForMember(d => d.Take, o => o.MapFrom(s => s.Take))
                    .ForMember(d => d.Total, o => o.MapFrom(s => s.Total));
            });
            var mapper = config.CreateMapper();
            var source = new TrackingKeyStatic<NotReleventClassForThisExample>()
            {
                Skip = 10,
                Take = 50,
                Total = 123456,
                NewTrackingKey = 987654
            };
            var actual = mapper.Map<MyEntitiesDbFirstModel>(source);
            Assert.AreEqual(10, actual.Skip);//ok
            Assert.AreEqual(50, actual.Take);//ok
            Assert.AreEqual(123456, actual.Total);//ok
            Assert.AreEqual(987654, actual.TrackingKey);//failed
        }

        [TestMethod]
        public void TestWitTrackingKeyStaticAsSource_WORKING()
        {
            var config = new MapperConfiguration(cfg => {
                cfg.CreateMap<TrackingKeyStatic<NotReleventClassForThisExample>, MyEntitiesDbFirstModel>()
                    .ForMember(d => d.TrackingKey, o => o.MapFrom(s => s.NewTrackingKey));
                cfg.CreateMap<IBatchProcessing, MyEntitiesDbFirstModel>()
                    .ForMember(d => d.Skip, o => o.MapFrom(s => s.Skip))
                    .ForMember(d => d.Take, o => o.MapFrom(s => s.Take))
                    .ForMember(d => d.Total, o => o.MapFrom(s => s.Total));
            });
            var mapper = config.CreateMapper();
            var source = new TrackingKeyStatic<NotReleventClassForThisExample>()
            {
                Skip = 10,
                Take = 50,
                Total = 123456,
                NewTrackingKey = 987654
            };
            var actual = mapper.Map<MyEntitiesDbFirstModel>(source);
            Assert.AreEqual(10, actual.Skip);//ok
            Assert.AreEqual(50, actual.Take);//ok
            Assert.AreEqual(123456, actual.Total);//ok
            Assert.AreEqual(987654, actual.TrackingKey);//work fine
        }
    }
    public interface ITrackingKey
    {
        int NewTrackingKey { get; set; }
        List<object> Records { get; set; }
    }
    public interface IBatchProcessing
    {
        int Skip { get; set; }
        int Take { get; set; }
        int Total { get; set; }
    }
    public class TrackingKey<T> : ITrackingKey
    {
        private List<object> _records;

        public int NewTrackingKey { get; set; }

        public List<T> Records  //not relevent for question, it just for implementing interface
        {
            get { return _records?.Cast<T>()?.ToList(); }
            set { _records = value?.Cast<object>()?.ToList(); }
        }

        List<object> ITrackingKey.Records //not relevent for question, it just for implementing interface
        {
            get { return _records; }
            set { _records = value; }
        }
    }
    public class TrackingKeyStatic<T> : TrackingKey<T>, IBatchProcessing
    {
        public int Skip { get; set; }
        public int Take { get; set; }
        public int Total { get; set; }
    }
    public class MyEntitiesDbFirstModel
    {
        public int Skip { get; set; }
        public int Take { get; set; }
        public int Total { get; set; }
        public int TrackingKey { get; set; }
    }

    public class NotReleventClassForThisExample { public int MyProperty { get; set; }}
}

我能够使用一个小的 "hacky" 包装方法让它工作:

    public static MyEntitiesDbFirstModel MapToMyDbModel<T>(TrackingKeyStatic<T> trackingKey, IMapper mapper)
    {
        var interimTypeObject = new TrackingKey<T>()
        {
            NewTrackingKey = trackingKey.NewTrackingKey
        };

        var actual = mapper.Map<MyEntitiesDbFirstModel>(trackingKey);
        mapper.Map<ITrackingKey, MyEntitiesDbFirstModel>(interimTypeObject, actual);

        return actual;
    }   

这是 fiddle - https://dotnetfiddle.net/XAjQB4

您也许可以进一步摆脱丑陋 - 当您使用 TrackingKeyStatic<T> 时,AutoMapper 似乎无法在此处选择正确的地图,但在执行 TrackingKey<T>.[=14 时没有问题=]