如何使用 AutoMapper 深度克隆包含 IList 属性的对象

发布于 2024-09-13 01:07:19 字数 1848 浏览 3 评论 0原文

我正在尝试使用 AutoMapper 深度克隆以下类:

public class MainData
{
    public MainData()
    {
        Details = new List<Detail>();
    }

    public int Id { get; private set; }
    public DateTime LastUpdate { get; private set; }
    public IList<Detail> Details { get; private set; }
    public int Prop1 { get; set; }
    public int Prop2 { get; set; }

    public void AddDetail(Detail detail)
    {
        Details.Add(detail);
    }

    public void RemoveDetail(Detail detail)
    {
        Details.Remove(detail);
    }

    public MainData Clone()
    {
        Mapper.Reset();
        Mapper.CreateMap<MainData, MainData>().ForMember(d => d.Id, o => o.Ignore());
        // Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore()); // REMOVED
        var newMainData = new MainData();
        Mapper.Map(this, newMainData);
        newMainData.Details = this.Details.Select(item => item.Clone()).ToList(); // ADDED
        return newMainData;
    }
}

public class Detail
{
    public int Id { get; private set; }
    public string Name { get; set; }
    public double Area { get; set; }
    public double Height { get; set; }

    public Detail Clone() // ADDED
    {
        Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore());
        var newDetail = new Detail();
        Mapper.Map(this, newDetail);
        return newDetail;
    }
}

Clone 方法对于 MainData 属性工作正常,但似乎只对详细信息列表进行浅表复制。我尝试添加 .ForMember(d => d.Details, o => o.UseDestinationValue()) 但这根本不会复制详细信息列表。如何获得详细信息列表深度克隆,即,我最终得到两个完全独立的对象,包括所有列表项?

更新: 我需要排除 Id 属性,因为我将这些对象与 NHibernate 一起使用,因此不确定 Serialized 解决方案是否会执行此操作。

更新2:修改了上面的代码以克隆IList。这似乎工作正常,因为我可以排除使 NHibernate 认为它已经被保存的属性。

I am trying to deep clone the following class using AutoMapper:

public class MainData
{
    public MainData()
    {
        Details = new List<Detail>();
    }

    public int Id { get; private set; }
    public DateTime LastUpdate { get; private set; }
    public IList<Detail> Details { get; private set; }
    public int Prop1 { get; set; }
    public int Prop2 { get; set; }

    public void AddDetail(Detail detail)
    {
        Details.Add(detail);
    }

    public void RemoveDetail(Detail detail)
    {
        Details.Remove(detail);
    }

    public MainData Clone()
    {
        Mapper.Reset();
        Mapper.CreateMap<MainData, MainData>().ForMember(d => d.Id, o => o.Ignore());
        // Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore()); // REMOVED
        var newMainData = new MainData();
        Mapper.Map(this, newMainData);
        newMainData.Details = this.Details.Select(item => item.Clone()).ToList(); // ADDED
        return newMainData;
    }
}

public class Detail
{
    public int Id { get; private set; }
    public string Name { get; set; }
    public double Area { get; set; }
    public double Height { get; set; }

    public Detail Clone() // ADDED
    {
        Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore());
        var newDetail = new Detail();
        Mapper.Map(this, newDetail);
        return newDetail;
    }
}

The Clone method works fine for the MainData properties but seems to only do a shallow copy of the Details list. I have tried adding .ForMember(d => d.Details, o => o.UseDestinationValue()) but this does not copy the Details list at all. How can I get the Details list deep cloned as well ie, so I end up with two totally independent objects including all the list items?

UPDATE: I need to exclude the Id property as I am using these objects with NHibernate so not sure if the Serializable solution will do this.

UPDATE2: Modified the above code to clone the IList too. This seems to work fine as I can exclude properties that make NHibernate think it has already been saved.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

撞了怀 2024-09-20 01:07:19

这是一种使用 ValueInjecter 的解决方案,

        var clone = new MainData();

        clone.InjectFrom(mainData);//mainData is your source

        mainData.Details.AsParallel.ForAll(detail => 
        {
            var dc = new Detail();
            dc.InjectFrom(detail);
            clone.AddDetail(dc);
        });

不会设置具有私有设置器的属性,(看起来合理)
祝你好运;)

编辑:
我做了一个更好的解决方案,请看这里

here is one solution with the ValueInjecter

        var clone = new MainData();

        clone.InjectFrom(mainData);//mainData is your source

        mainData.Details.AsParallel.ForAll(detail => 
        {
            var dc = new Detail();
            dc.InjectFrom(detail);
            clone.AddDetail(dc);
        });

the properties that have private setters are not going to be set, (looks reasonable)
good luck ;)

EDIT:
I did a better solution look here

鸢与 2024-09-20 01:07:19

AutoMapper 并不是真正的克隆 API。相反,我会使用这个克隆技巧:

public static object CloneObject(object obj)
{
    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, 
             new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, obj);
        memStream.Seek(0, SeekOrigin.Begin);
        return binaryFormatter.Deserialize(memStream);
    }
}

它并不适用于所有情况,但它非常方便。

AutoMapper isn't really a cloning API. I would instead use this cloning trick:

public static object CloneObject(object obj)
{
    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, 
             new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, obj);
        memStream.Seek(0, SeekOrigin.Begin);
        return binaryFormatter.Deserialize(memStream);
    }
}

It doesn't work for every situation, but it's pretty handy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文