C# 自动映射MapFrom无效

C# 自动映射MapFrom无效,c#,automapper,C#,Automapper,编辑:添加带有参数信息的构造函数 我使用的是AutoMapper 9.0版和.Net Core 2.1版 下面的单元测试应该更改stockRecord.ClosePrice的值,但如果存在第二个构造函数,则不会更改。注释掉后,第二个构造函数closePrice的正确值为100 股票记录类 [DynamoDBTable("StockRecord")] public class StockRecord { [DynamoDBHashKey] public string TickerS

编辑:添加带有参数信息的构造函数

我使用的是AutoMapper 9.0版和.Net Core 2.1版 下面的单元测试应该更改stockRecord.ClosePrice的值,但如果存在第二个构造函数,则不会更改。注释掉后,第二个构造函数
closePrice
的正确值为100

股票记录类

[DynamoDBTable("StockRecord")]
public class StockRecord
{
    [DynamoDBHashKey]
    public string TickerSymbol { get; set; }

    [DynamoDBRangeKey]
    public DateTime TradingDay { get; private set; }

    public float OpenPrice { get; private set; }
    public float ClosePrice { get; private set; }
    public float DayHighestPrice { get; private set; }
    public float DayLowestPrice { get; private set; }

    public StockRecord() {}

    // add this constructor below will make the unit test below fail, ClosePrice will stay value of 20
    // Once Comment out this constructor, unit test will pass, ClosePrice value will change to 100
    public StockRecord(string tickerSymbol, DateTime tradingDay, float openPrice, float closePrice, float dayHighestPrice, float dayLowestPrice)
    {
        TickerSymbol = tickerSymbol;
        TradingDay = tradingDay;
        OpenPrice = openPrice;
        ClosePrice = closePrice;
        DayHighestPrice = dayHighestPrice;
        DayLowestPrice = dayLowestPrice;
    }       
}
StockRecordDto类

public class StockRecordDto
{
    public string TickerSymbol { get; set; }
    public DateTime TradingDay { get; set; }
    public float OpenPrice { get; set; }
    public float ClosePrice { get; set; }
    public float DayHighestPrice { get; set; }
    public float DayLowestPrice { get; set; }
}
单元测试

[Fact]
public void Test1()
{
    var configuration = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<StockRecord, StockRecordDto>()
        .ForMember(dst => dst.ClosePrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
        .ReverseMap()
        .ForMember(dst => dst.ClosePrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));
    });
    configuration.AssertConfigurationIsValid();

    var mapper = configuration.CreateMapper();

    var stockRecordDto = new StockRecordDto
    {
        TickerSymbol = "ticker 01",
        TradingDay = DateTime.Now,
        OpenPrice = 10,
        ClosePrice = 20,
        DayHighestPrice = 30,
        DayLowestPrice = 5
    };

    StockRecord stockRecord = mapper.Map<StockRecord>(stockRecordDto);
    Assert.Equal(100, stockRecord.ClosePrice);
}
[事实]
公共void Test1()
{
var配置=新的MapperConfiguration(cfg=>
{
cfg.CreateMap()
.ForMember(dst=>dst.ClosePrice,op=>op.MapFrom(src=>src.ClosePrice>0?300:400))
.ReverseMap()
.ForMember(dst=>dst.ClosePrice,op=>op.MapFrom(src=>src.ClosePrice>0-100:200));
});
assertConfigurationsValid();
var mapper=configuration.CreateMapper();
var stockRecordDto=新的stockRecordDto
{
TickerSymbol=“ticker 01”,
TradingDay=日期时间。现在,
OpenPrice=10,
收盘价=20,
日最高价格=30,
日最低价格=5
};
StockRecord=mapper.Map(stockRecordDto);
断言。相等(100,股票记录。收盘价);
}
根据autoMapper的文档,stockRecord.ClosePrice应更改为100。但现在仍然是20岁。 我花了整个下午的时间在这上面,但还是想不出来。 我可以用工厂方法替换构造函数,但我仍然不理解为什么带参数的构造函数会出现问题

如果这是一个bug,我会在AutoMapper的github上发布一个问题


谢谢。

如果您想更改
DayLowestPrice
,那么在映射中,使用“作为目标”字段
DayLowestPrice
,而不是
ClosePrice

cfg.CreateMap<StockRecord, StockRecordDto>()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
        .ReverseMap()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));
说明你的目标需要如何构造。您可以找到有关它在上的行为方式的更多信息

Edit2

您也可以使用
ConstructUsing
,但在这种情况下,您应该将属性设置为只读(从属性中删除
private set;
),并指定所有构造函数参数。在这种情况下,可以避免硬编码构造函数参数名

public class StockRecord
{
       ***

    public float ClosePrice { get; }

       ***
}

cfg.CreateMap<StockRecordDto, StockRecord>()
  .ConstructUsing(s => new StockRecord(s.TickerSymbol, s.TradingDay, s.OpenPrice, s.ClosePrice > 0 ? 100 : 200, s.DayHighestPrice, s.DayLowestPrice));
公共类股票记录
{
***
公共价格{get;}
***
}
cfg.CreateMap()
.构造使用(s=>新股票记录(s.TickerSymbol,s.TradingDay,s.OpenPrice,s.ClosePrice>0?100:200,s.DayHighestPrice,s.DayLowestPrice));

如果要更改
DayLowestPrice
,则在映射中使用“作为目标”字段
DayLowestPrice
,而不是
ClosePrice

cfg.CreateMap<StockRecord, StockRecordDto>()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 300 : 400))
        .ReverseMap()
        .ForMember(dst => dst.DayLowestPrice, op => op.MapFrom(src => src.ClosePrice > 0 ? 100 : 200));
说明你的目标需要如何构造。您可以找到有关它在上的行为方式的更多信息

Edit2

您也可以使用
ConstructUsing
,但在这种情况下,您应该将属性设置为只读(从属性中删除
private set;
),并指定所有构造函数参数。在这种情况下,可以避免硬编码构造函数参数名

public class StockRecord
{
       ***

    public float ClosePrice { get; }

       ***
}

cfg.CreateMap<StockRecordDto, StockRecord>()
  .ConstructUsing(s => new StockRecord(s.TickerSymbol, s.TradingDay, s.OpenPrice, s.ClosePrice > 0 ? 100 : 200, s.DayHighestPrice, s.DayLowestPrice));
公共类股票记录
{
***
公共价格{get;}
***
}
cfg.CreateMap()
.构造使用(s=>新股票记录(s.TickerSymbol,s.TradingDay,s.OpenPrice,s.ClosePrice>0?100:200,s.DayHighestPrice,s.DayLowestPrice));

对不起,我是说ClosePrice,我在第一次发布问题时复制了错误的文本。已更新问题。复制粘贴您的代码对我来说效果很好,ClosePrice更改为100。由于您没有提供记录类,我只能猜测,您的
ClosePrice
成员
StockRecord
上没有setter或private setter。谢谢您的回复。我在课堂上更新了问题。我还发现,是带参数的构造函数导致了问题,一旦我注释掉了第二个构造函数,单元测试就会通过。然而,我只是不明白为什么构造函数会导致这个问题。我需要一天的方式或映射吗?我也进行了测试,即使我通过从StockRecord类中为我的setters取出“private”来公开所有属性,只要带参数的构造函数存在,单元测试就会失败。你可以检查我的编辑,也可以查看文档中的页面。对不起,我是指ClosePrice,当我第一次发布问题时,我抄错了文本。已更新问题。复制粘贴您的代码对我来说效果很好,ClosePrice更改为100。由于您没有提供记录类,我只能猜测,您的
ClosePrice
成员
StockRecord
上没有setter或private setter。谢谢您的回复。我在课堂上更新了问题。我还发现,是带参数的构造函数导致了问题,一旦我注释掉了第二个构造函数,单元测试就会通过。然而,我只是不明白为什么构造函数会导致这个问题。我需要一天的方式或映射吗?我也进行了测试,即使我通过从StockRecord类中为我的setters取出“private”来公开所有属性,只要带参数的构造函数存在,单元测试就会失败。你可以检查我的编辑,也可以查看文档中的页面。