【问题标题】:Automapper: using Type Converter and Value Resolvers for the same typesAutomapper:对相同类型使用类型转换器和值解析器
【发布时间】:2015-11-26 02:58:06
【问题描述】:

我有很多 DTO 必须映射到我的域的对象。一般来说,与货币价值的映射需要应用四舍五入规则。这适用于 95% 以上的情况,但我有一些数据需要不同的舍入规则。我打算做下一个:

1) 为一般舍入规则创建一个 ITypeConverter,该规则应用于此类型转换的默认值。

2) 为特殊的舍入情况创建一个 ValueResolver,并在成员映射中指定它们的用途。

我创建了一个测试用例来尝试我的方法,但是在对特殊情况应用 ValueResolver 之后,AutoMapper 使用 TypeConverter 来获取最终值,使用一般规则。

这是一个错误的方法??可能是我错过了什么??

然后是测试用例:

[TestFixture]
public class RoundingTests
{
    public class MoneyConverter : ITypeConverter<decimal, decimal>
    {
        public decimal Convert(ResolutionContext context)
        {
            return Math.Round((decimal)context.SourceValue, 2, MidpointRounding.AwayFromZero);
        }
    }

    public class Money12Resolver : ValueResolver<decimal, decimal>
    {
        protected override decimal ResolveCore(decimal source)
        {
            return Math.Round(source, 12, MidpointRounding.AwayFromZero);
        }
    }

    public class PercentResolver : ValueResolver<decimal, decimal>
    {
        protected override decimal ResolveCore(decimal source)
        {
            return Math.Round(source, 4, MidpointRounding.AwayFromZero);
        }
    }
    internal class Source
    {
        public decimal Price { get; set; }
        public decimal Percent { get; set; }
        public decimal Prorate { get; set; }
    }

    internal class Destination
    {
        public decimal Price { get; set; }
        public decimal Percent { get; set; }
        public decimal Prorate { get; set; }
    }

    [Test]
    public void MappingTest()
    {
        Mapper.CreateMap<decimal, decimal>().ConvertUsing<MoneyConverter>();

        Mapper.CreateMap<Source, Destination>()
            .ForMember(d => d.Percent, o => o.ResolveUsing<PercentResolver>().FromMember(s => s.Percent))
            .ForMember(d => d.Prorate, o => o.ResolveUsing<Money12Resolver>().FromMember(s => s.Prorate));

        Mapper.AssertConfigurationIsValid();

        var source = new Source
                     {
                         Price = 12345.6789m,
                         Percent = 0.123456m,
                         Prorate = 123.123451234512345m
                     };

        var convertion = Mapper.Map<Destination>(source);

        Assert.That(convertion, Is.Not.Null);

        Assert.That(convertion.Price, Is.EqualTo(12345.68m));
        Assert.That(convertion.Percent, Is.EqualTo(0.1235m));
        Assert.That(convertion.Prorate, Is.EqualTo(123.123451234512m));
    }
}

测试结果:

  Expected: 0.1235m
  But was:  0.12m

【问题讨论】:

    标签: automapper automapper-3


    【解决方案1】:

    您告诉 AutoMapper 使用您的 MoneyConverter 转换所有十进制->十进制映射。事实上,AutoMapper 确实使用了您的解析器(设置一个断点来查看),但解析的结果是一个十进制值,然后由您应用的 MoneyConverter 使用。

    注意:这似乎是 AutoMapper 的设计;我看不到覆盖类型转换器的方法。

    并非所有小数属性都代表金钱,因此您可能需要采用不同的方法。还要问自己,您是纯粹为用于表示的值四舍五入,还是可能失去您希望在这些域对象中保留的精度?如果你真的需要四舍五入,你可以明确地为每个成员设置一个解析器,完全跳过转换器。或者,您可以忽略属于异常的成员并使用.ConstructUsing(...) 处理它。

    但由于您最初的问题涉及使用相同类型的解析器和转换器,因此您可以通过以下方法使其工作:


    基本上,我们希望转换器跳过某些属性的默认转换。我们不能通过配置来完成,所以我们必须在运行时完成。假设您可以访问 Destination 类,只需使用自定义属性装饰具有非默认行为的属性。

    class PercentAttribute : Attribute
    {   }
    
    class Destination
    {
        [Percent]
        public decimal Percent { get; set; }
        ...
    }
    

    然后,您可以在您的转换器中查找 [Percent] 的属性并返回来自您的 PercentResolver 的源值。

    public class MoneyConverter : ITypeConverter<decimal, decimal>
    {
        public decimal Convert(ResolutionContext context)
        {
            var propInfo = context.PropertyMap.DestinationProperty.MemberInfo;
            bool isPercent = propInfo.GetCustomAttributes(typeof(PercentAttribute), true).Any();
            if (isPercent) return (decimal)context.SourceValue;
    
            return Math.Round((decimal)context.SourceValue, 2, MidpointRounding.AwayFromZero);
        }
    }
    

    如果您要走这条路,只需让转换器根据属性进行 Money、Percent 和 Money12 转换,并完全跳过解析器。

    【讨论】:

      猜你喜欢
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 2012-02-25
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      相关资源
      最近更新 更多