【问题标题】:Copy properties recursively with FastMember使用 FastMember 递归复制属性
【发布时间】:2019-09-26 14:28:19
【问题描述】:

我有两个来自这个类的对象:

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<B> Bs { get; set; }
}

public class B
{
    public string Description { get; set; }
    public IList<C> Cs { get; set; }
}

public class C
{
    public string Description { get; set; }
}

现在我想用 FastMember 遍历两个对象实例的所有属性,并将属性从 object 1 复制到 object 2

这是我到目前为止得到的(不工作!)

// Set accessors
var sourceAccessor = ObjectAccessor.Create(object1);
var targetAccessor = ObjectAccessor.Create(object2);

foreach (var sourceItem in (IList)sourceAccessor.Target)
{
    var targetItemAccessor = ObjectAccessor.Create(targetAccessor.Target);
    var sourceItemAccessor = ObjectAccessor.Create(sourceItem);

    // Overwrite property
    targetItemAccessor[p] = sourceItemAccessor[p];
}

这段代码显然不起作用...有什么想法吗?谢谢!

【问题讨论】:

    标签: c# asp.net fastmember


    【解决方案1】:

    您可以在TypeAccessor 的帮助下创建一个shallow copy,使用类似:

    var sourceAccessor = ObjectAccessor.Create(object1);
    var targetAccessor = ObjectAccessor.Create(object2);
    
    var access = TypeAccessor.Create(typeof(A));
    var members = access.GetMembers();
    
    foreach (var member in members)
    {
        targetAccessor[member.Name] = sourceAccessor[member.Name];
    }
    

    查看FastMember tests 的用法示例。

    对于深拷贝,您可以检查属性名称或使用property type 来确定是应用deep copy of lists 还是浅拷贝就足够了。

    编辑:这是一个简化版本的示例,它递归复制IList 类型的属性(请参阅此question,了解如何确定哪个属性是列表),假设源对象和目标对象的列表具有相同的长度:

    private static void MirrorObject(object object1, object object2)
    {
        var sourceAccessor = ObjectAccessor.Create(object1);
        var targetAccessor = ObjectAccessor.Create(object2);
    
        var access = TypeAccessor.Create(object1.GetType());
        var members = access.GetMembers();
    
        foreach (var member in members)
        {
            if (member.Type.IsGenericType && (member.Type.GetGenericTypeDefinition() == typeof(IList<>)))
            {
                var list1 = (IList)sourceAccessor[member.Name];
                var list2 = (IList)targetAccessor[member.Name];
                if (list1.Count != list2.Count)
                {
                    throw new ArgumentException("Lists need to be of the same length.");
                }
                for (var i = 0; i < list1.Count; ++i)
                {
                    MirrorObject(list1[i], list2[i]);
                }
            }
            else
            {
                targetAccessor[member.Name] = sourceAccessor[member.Name];
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答!假设我想递归地复制属性,这意味着我想遍历IList&lt;B&gt;IList&lt;C&gt; 并复制那些嵌套的属性?
    • 不客气,我更新了答案以包含该用例的示例。
    • 我目前正在努力完成这项工作。但是在member.Type.IsGenericType &amp;&amp; (member.Type.GetGenericTypeDefinition() == typeof(IList&lt;&gt;)) 部分,它还检测到String 作为列表...
    • 我无法重现这个,例如:var member = "test"; var isList = member.GetType().IsGenericType &amp;&amp; (member.GetType().GetGenericTypeDefinition() == typeof(IList&lt;&gt;)); 导致 false
    • @user7217806 是的,对不起,我在代码中犯了一个错误,并将一个奇怪的类型传递给了 fastmember 框架(来自 newtonsoft JSON 框架的 json 实例)。我不确切知道哪些是不同的,但那种物体有点奇怪,这就是我的问题的原因。所以我删除了我的问题并忘记了这个评论。如果我使用“普通”对象,一切正常,在我的场景中,只有“普通”对象必须被管理,所以最终没有问题。
    猜你喜欢
    • 2016-06-02
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    相关资源
    最近更新 更多