如何指定 automapper 异常导致的数据?
Posted
技术标签:
【中文标题】如何指定 automapper 异常导致的数据?【英文标题】:How to specify automapper exception caused data? 【发布时间】:2021-08-13 12:17:06 【问题描述】:我正在使用第三个工具从文件中读取坐标值,并且工具将数据转换为 Point
类集合。
public class Point
public string Lon get;set;
public string Lat get;set;
public string Elevation get;set;
我想使用自动映射器将Point
类映射到PointEntity
。
public class PointEntity
public float Lon get;set;
public float Lat get;set;
public float Elevation get;set;
我使用 Automapper 创建了一个地图。
public class LocationProfile : Profile
public LocationProfile()
CreateMap<Point, PointEntity>();
我已经创建了一个通用的映射器扩展来映射列表。
public static class MapperHelper
public static TDest MapTo<TDest>(this object src)
return (TDest)AutoMapper.Mapper.Map(src, src.GetType(), typeof(TDest));
IList<Point> data = readData<Point>("file");
var mapped = data.MapTo<PointEntity>();
但有时用户可能会在文件中输入错误的类型条目,如下所示。
Lon Lat Elevation
--- --- ---------
11.5 25.6 80.56
12ab 89.87 14.83
1.7 x.8 9.3
在这种情况下,代码会抛出异常。
那么我怎样才能找到哪一行和哪一个值是错误的类型呢? (比如row1和Lon值不对)
【问题讨论】:
【参考方案1】:改变你的设计思维。映射只是将一个数据传输到另一个数据。而 automapper 非常擅长这项任务。把事情简单化。所以,尽量保持简单。我读到您想在映射期间执行验证并提供有关它的信息。这使得映射更加复杂。在我的设计中,我不会让这种情况在映射过程中发生。在映射之前验证此信息。使用验证规则类在映射之前对其进行迭代。或者在读取时验证数据,以便您可以立即告知行和列位置。
示例
使用 ConvertUsing(但如果之前验证则不需要)步骤来实施
public class LocationProfile : Profile
public LocationProfile()
CreateMap<Point, PointEntity>().ConvertUsing<PointEntityConverter>();
public class PointEntityConverter : ITypeConverter<Point, PointEntity>
public PointEntity Convert(Point source, PointEntity destination, ResolutionContext context)
if (destination == null)
destination = new PointEntity();
destination.Lon = Parse(source.Lon, nameof(source.Lon));
destination.Lat = Parse(source.Lat, nameof(source.Lat));
destination.Elevation = Parse(source.Elevation, nameof(source.Elevation));
return destination;
private float Parse(string s, string paramName)
if (float.TryParse(s, out float result))
return result;
throw new ArgumentException($"Invalide value (s) for parameter paramName", paramName);
实施
private readonly IMapper mapper;
private readonly IValidator<Point> validator;
public HowToSpecifyAutomapperExceptionCausedData(IMapper mapper)
this.mapper = mapper;
this.validator = new PointValidator();
public void Example()
var data = readData<Point>("file");
for (int i = 0; i < data.Count; i++)
validator.AssertValide(data[i], (m, p) => OnInvalidArgument(m, p, i));
var mapped = mapper.Map<IList<PointEntity>>(data);
private void OnInvalidArgument(string message, string paramName, int index)
throw new ArgumentException($"message on index index", paramName);
验证器
internal interface IValidator<T>
void AssertValide(T value, InvalideArgumentHandler handler);
internal delegate void InvalideArgumentHandler(string message, string paramName);
internal class PointValidator : IValidator<Point>
public void AssertValide(Point value, InvalideArgumentHandler handler)
AssertValideFloat(value.Lon, nameof(value.Lon), handler);
AssertValideFloat(value.Lat, nameof(value.Lat), handler);
AssertValideFloat(value.Elevation, nameof(value.Elevation), handler);
private void AssertValideFloat(string s, string paramName, InvalideArgumentHandler handler)
if (!float.TryParse(s, out float result))
handler($"Invalide value (s) for parameter paramName", paramName);
为什么要使用委托? 其他示例通过收集所有(也为每个参数 [lon, lat, ...])无效参数。 现在看看使用处理程序的能力。
public void Example()
var data = readData<Point>("file");
var errors = new List<string>();
for (int i = 0; i < data.Count; i++)
validator.AssertValide(data[i], (m, p) => errors.Add($"m on index i"));
if (errors.Any()) //using System.Linq;
throw new ApplicationException(string.Join(Environment.NewLine, errors));
var mapped = mapper.Map<IList<PointEntity>>(data);
【讨论】:
你的意思是在Point类中创建一个名为Validate的方法。并尝试解析属性。这是一种手动方式。 实现部分是单独的类吗? 你问,“实现部分是一个单独的类吗?”我的第一反应是盲目的yes。因为拥有尽可能小的构建块并在它们所属的地方做事总是更好。但在那之后我会说这取决于情况。在这种情况下你会做什么。我根据您的起始问题给出了一个实现。 (我确实在一个类中编写了示例并为这个答案剪掉了它。请参阅构造函数部分:public HowToSpecifyAutomapperExceptionCausedData(IMapper mapper))以上是关于如何指定 automapper 异常导致的数据?的主要内容,如果未能解决你的问题,请参考以下文章