在Automapper for JObject中为一个公共访问模式

时间:2017-01-19 23:09:05

标签: json.net automapper-5

我从一个JObject映射到一个自定义类,它工作正常,但我宁愿告诉它一次执行这种默认类型的映射,而不是必须为每个属性执行.MapFrom。大多数源“属性”只是目标上Pascal案例属性名称的小写下划线版本。

由于JObject没有我想要的值作为属性,我必须通过MapFrom索引它们(我不能使用SourceMemberNamingConvention / DestinationMemberNamingConvention)。所以我想要一个表达式,我可以通过像ForAllOtherMembers这样的东西来使用来从JObject应用这个默认值检索,但我不能它工作......我有什么选择?

我尝试过使用ResolveUsing方法,我也必须使用ConstructedBy方法,但ResolveUsing返回一个void(现在版本为5),所以我不能对它进行.ConstructedBy()。

下面我不得不做每个MapFrom,即使它们遵循相同的访问模式:

   MapperConfiguration MapperConfig = new MapperConfiguration(cfg => {
   cfg.CreateMap<string, bool>().ConvertUsing<BooleanTypeConverter>();
   cfg.CreateMap<JObject, FiscalYear>()
       .ForMember("EmployeeName", 
            options => options.MapFrom(jo => jo["employee_name"]))
       .ForMember("YearName", 
            options => options.MapFrom(jo => jo["year_name"]));

更新: 我继续前进,只是用手动方式做了更多,并用代表替换了字符串

public static class AutoMapperConfig
{
    public static MapperConfiguration MapperConfig = new MapperConfiguration(cfg => {
        cfg.CreateMap<string, bool>().ConvertUsing<BooleanTypeConverter>();

        cfg.CreateMap<JToken, FiscalYear>()
            .Map(d => d.EmployeeName)
            .Map(d => d.Year, "int_year")
            .Map(d => d.Name, "year");
    });
}

public static class MappingExpressionExtensions
{
    private static readonly MatchEvaluator ToSnakeCaseEvaluator = m =>
    {
        string match = m.ToString();
        return "_" + char.ToLower(match[0]) + match.Substring(1);
    };

    public static IMappingExpression<JToken, TDest> Map<TDest, TDestProp>(this IMappingExpression<JToken, TDest> map,
        Expression<Func<TDest, TDestProp>> propertyExpression, string sourceName = null)
    {
        var propertyName = propertyExpression.PropertyName();
        sourceName = string.IsNullOrWhiteSpace(sourceName)
                    ? new Regex("([A-Z])").Replace(propertyName, ToSnakeCaseEvaluator).TrimStart('_')
                    : sourceName;
        var propType = typeof(TDestProp);
        if (propType == typeof(bool))
        {
            // in order for BooleanTypeConverter to work, convert to string and run as a normal mapping
            map.ForMember(propertyExpression.PropertyName(), o => o.MapFrom(jo => jo[sourceName].ToString()));
            return map;
        }

        var isNullableGenericType = propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>);
        var underlyingType = isNullableGenericType ? Nullable.GetUnderlyingType(propType) : propType;
        TypeConverter converter = TypeDescriptor.GetConverter(underlyingType);

        map.ForMember(propertyName,
            o => o.MapFrom(jo => (isNullableGenericType && string.IsNullOrWhiteSpace(jo[sourceName].ToString()))
                    || (IsNumeric(jo[sourceName]) && string.IsNullOrWhiteSpace(jo[sourceName].ToString()))
                        ? 0 : converter.ConvertFrom(jo[sourceName].ToString())));

        return map;
    }

    public static bool IsNumeric(object expression)
    {
        if (expression == null)
            return false;

        double number;
        return Double.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture),
            NumberStyles.Any, NumberFormatInfo.InvariantInfo, out number);
    }
}

public class BooleanTypeConverter : ITypeConverter<string, bool>
{
    /// <summary>
    /// Automapper version compatible with version 4.x
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public bool Convert(ResolutionContext context)
    {
        switch (context.SourceValue.ToString().ToLower().Trim())
        {
            case "true":
            case "yes":
            case "y":
            case "1":
                return true;
        }

        return false;
    }

    //// Automapper version compatible with version 5.0+
    //public bool Convert(string source, bool destination, ResolutionContext context)
    //{
    //    switch (source.ToLower().Trim())
    //    {
    //        case "true":
    //        case "yes":
    //        case "y":
    //        case "1":
    //            return true;
    //    }

    //    return false;
    //}  

// put this in static class
    public static string PropertyName<T, TProperty>(this Expression<Func<T, TProperty>> property)
{
  if (property.Body is MemberExpression)
    return ((MemberExpression) property.Body).Member.Name;
  return ((MemberExpression) ((UnaryExpression) property.Body).Operand).Member.Name;
}
}

0 个答案:

没有答案