C# 为什么每次引用源集合时,Automapper都会将具体集合映射到新实例?
我有一个源对象,其中包含对同一集合的2个引用。如果将源类型映射到结构等效的目标类型,AutoMapper将在目标实例中创建集合的两个实例C# 为什么每次引用源集合时,Automapper都会将具体集合映射到新实例?,c#,.net,automapper,automapper-3,C#,.net,Automapper,Automapper 3,我有一个源对象,其中包含对同一集合的2个引用。如果将源类型映射到结构等效的目标类型,AutoMapper将在目标实例中创建集合的两个实例 class SourceThing { public string Name { get; set; } public List<int> Numbers { get; set; } public List<int> MoreNumbers { get; set; } } class TargetThing {
class SourceThing
{
public string Name { get; set; }
public List<int> Numbers { get; set; }
public List<int> MoreNumbers { get; set; }
}
class TargetThing
{
public string Name { get; set; }
public List<int> Numbers { get; set; }
public List<int> MoreNumbers { get; set; }
}
这是AutoMapper中具体集合的默认映射行为吗?通过测试,我意识到如果我将
List
映射到List
,我就实现了我想要的行为,但我不明白为什么。如果AutoMapper跟踪引用并且不重新映射映射对象,它不会看到source.MoreNumbers
指向与source.Numbers
相同的列表,并相应地设置目标吗?行为没有问题,这只是AutoMapper映射的方式
在顶部部分,创建一个数字列表,然后将其应用于第二个数字列表。然后可以进行比较,它们是相同的,因为对象有两个指向同一列表的指针。它没有复制数字,它只是做了一个新的参考,就像你问的那样
现在,转到汽车制造商。它贯穿并从一个对象映射到一个等效对象。它分别映射每个属性,复制信息。因此,即使源代码有更多的数字作为指向同一列表的指针,automapper也会分别映射每个数字。为什么?它是映射属性,而不是检查属性指针。而且,在大多数情况下,您不希望它这样做
这有意义吗
如果最终目标是通过测试,那么问题不是“数字和更多数字是否指向同一对象”,而是“数字和更多数字是否包含完全相同的列表”。在第一个例子中,两者的答案都是肯定的,因为有一个对象(列表)表示数字和更多数字。在第二种情况下,答案是假,然后是真,因为列表是等效的,但它并不指向同一个确切的对象
如果你真的想让它成为同一个物体,你就必须以不同的方式玩这个游戏。如果您只是想知道列表中是否有相同的元素,那么请更改断言。行为没有问题,只是automapper如何映射 在顶部部分,创建一个数字列表,然后将其应用于第二个数字列表。然后可以进行比较,它们是相同的,因为对象有两个指向同一列表的指针。它没有复制数字,它只是做了一个新的参考,就像你问的那样 现在,转到汽车制造商。它贯穿并从一个对象映射到一个等效对象。它分别映射每个属性,复制信息。因此,即使源代码有更多的数字作为指向同一列表的指针,automapper也会分别映射每个数字。为什么?它是映射属性,而不是检查属性指针。而且,在大多数情况下,您不希望它这样做 这有意义吗 如果最终目标是通过测试,那么问题不是“数字和更多数字是否指向同一对象”,而是“数字和更多数字是否包含完全相同的列表”。在第一个例子中,两者的答案都是肯定的,因为有一个对象(列表)表示数字和更多数字。在第二种情况下,答案是假,然后是真,因为列表是等效的,但它并不指向同一个确切的对象
如果你真的想让它成为同一个物体,你就必须以不同的方式玩这个游戏。如果您只是想知道列表中是否有相同的元素,请更改断言。我做了更多的研究和修补。在内部,当映射引擎遍历对象图时,它会为每个源类型/目标类型选择最佳映射器。除非存在非标准映射(过于简化),否则引擎接下来将查找源和目标类型的注册映射器。如果找到一个,它将创建目标对象,然后遍历并映射所有属性。它还将目标对象放入
ResolutionContext.InstanceCache
,这是一个字典
。如果在同一根映射调用中再次遇到相同的源对象,它将从缓存中提取该对象,而不是浪费时间重新映射
但是,如果没有注册的映射器,引擎将选择下一个适用的映射器,在本例中是AutoMapper.Mappers.CollectionMapper
。集合映射器创建目标集合,枚举源集合并映射每个元素。它不会将目标对象添加到缓存中。这显然就是设计
解析上下文
我发现真正有趣的是对象是如何缓存在InstanceCache中的。键是当前ResolutionContext,其中包含源和目标类型以及源值。ResolutionContext重写GetHashCode()和Equals(),它们使用基础源值的相同方法。我可以在自定义类上定义相等,以便具有该类的多个相等但不同实例的源集合映射到具有对同一实例的多个引用的集合
class SourceThing
{
public string Name { get; set; }
public List<int> Numbers { get; set; }
public List<int> MoreNumbers { get; set; }
}
class TargetThing
{
public string Name { get; set; }
public List<int> Numbers { get; set; }
public List<int> MoreNumbers { get; set; }
}
这一类:
class EquatableThing
{
public string Name { get; set; }
public override bool Equals(object other)
{
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
return this.Name == ((EquatableThing)other).Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
将一个集合映射为两个相等(但独立)的对象,结果是一个集合具有指向同一对象的两个指针
public void MapCollectionWithTwoEqualItems()
{
Mapper.CreateMap<EquatableThing, EquatableThing>();
var thing1 = new EquatableThing() { Name = "foo"};
var thing2 = new EquatableThing() { Name = "foo"};
Assert.AreEqual(thing1, thing2);
Assert.AreEqual(thing1.GetHashCode(), thing2.GetHashCode());
Assert.AreNotSame(thing1, thing2);
// create list and map this thing across
var list = new List<EquatableThing>() { thing1, thing2};
var result = Mapper.Map<List<EquatableThing>, List<EquatableThing>>(list);
Assert.AreSame(result[0], result[1]);
}
public void MapCollectionWithTwoEqualItems()
{
CreateMap();
var thing1=new equalablething(){Name=“foo”};
var thing2=new equalablething(){Name=“foo”};
断言.AreEqual(事情1,事情2);
AreEqual(thing1.GetHashCode(),thing2.GetHashCode());
断言.不相同(第1项,第2项);
//创建一个列表,并将其映射到
var list=new list(){thing1,thing2};
var result=Mapper.Map(列表);
arest.arame(结果[0],结果[1]);
}
保留引用
一、 首先,我想知道为什么德福