仅从一个对象复制尚未填充到相同类型的另一个对象中的填充值

本文关键字:一个对象 填充 同类型 复制 | 更新日期: 2023-09-27 18:31:40

>我要求只从一个对象复制填充的值,这些值尚未填充到另一个相同类型的对象中。

例如,我们

传递了一个对象,它仅部分实例化了数据,我们读取数据库以获取对象的完全实例化版本 - 但是这可能还没有被提交到数据库的应用程序进行更改 - 因此我们需要将任何值从数据库版本移动到对象的传入版本 - 而不覆盖传入对象中可能已经存在的任何值(因为这些是最新的值)。

Adam Robinson在另一篇文章中建议的代码(见下文非常有用 - 谢谢!)是一个很好的起点。但是我需要扩展它 - 因为我只想复制尚未填充在目标对象上的值(即需要检查 destProperty 是否为空)。然而,作为一个额外的复杂性,在传入的对象中声明了内部复杂类型,此代码复制高级子组而不进入子组的各个属性(即使用根 cdt 声明的任何变量我可以尝试检查 null,但子 cdt 中的所有字段都只是简单地复制而不通过各个字段)。

任何帮助将不胜感激。

public static void CopyPropertyValues(object source, object destination)
{
    var destProperties = destination.GetType().GetProperties();
foreach (var sourceProperty in source.GetType().GetProperties())
{
    foreach (var destProperty in destProperties)
    {
        if (destProperty.Name == sourceProperty.Name && 
    destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType))
        {
            destProperty.SetValue(destination, sourceProperty.GetValue(
                source, new object[] { }), new object[] { });
            break;
        }
    }
}

}

仅从一个对象复制尚未填充到相同类型的另一个对象中的填充值

首先,您需要确定填充在书中的含义。确定后,编写以下IsDefaultValue方法的自己的版本。我所写的内容将以以下方式true回答:

  • 如果是bool则它需要具有false
  • 如果是int则需要0
  • 如果是任何class则需要null

所以这是我的方法版本:

public static bool IsDefaultValue(object @object) {
    if (null == @object)
        return true;
    else if (@object.GetType().IsValueType) {
        var isDefault = Activator.CreateInstance(@object.GetType()).Equals(@object);
        return isDefault;
    } else
        return false;
}

然后,假设你只对非索引器属性感兴趣,你没有层次结构,并且你将始终使用相同类型的对象调用此方法,您可以过滤掉那些在source中不是默认值但在destination中是默认值的属性。

然后,当目标属性中具有非默认值时,您可以递归遍历实例图。

请不要说我在这里写的只是你如何能够完成任务的演示。在您的特定场景中有一些复杂的细节,您需要自己解决,因为它们在您的问题中并不明显。

例如,我认为为递归遍历(remainingDepth参数)添加一个停止条件是个好主意

public static void CopyPropertyValues(object source, object destination, int remainingDepth = 3) {
    // we've reached the farthest point we're allowed to go to
    // anything beyond this point won't be affected by this method
    if (remainingDepth == 0)
        return;
    // just a check to make sure the following lines won't backfire
    if ((null == source) || (null == destination))
        throw new ArgumentNullException();
    // we'll need to also check that the 2 objects are of the same type
    var type = source.GetType();
    if (destination.GetType() != type)
        throw new ArgumentException("The two objects should be of the same type");
    var properties = type.GetProperties()
        // just filter out the properties which are indexers (if any)
        // and also those properties which are read or write only
        .Where(property => (property.GetIndexParameters().Length == 0) &&
                           property.CanRead && property.CanWrite);
    foreach (var property in properties) {
        var sourceValue = property.GetValue(source, null);
        var destValue = property.GetValue(destination, null);
        if (!IsDefaultValue(sourceValue))
            if (IsDefaultValue(destValue))
                property.SetValue(destination, sourceValue, null);
            else
                if (sourceValue.GetType() == destValue.GetType())
                    CopyPropertyValues(sourceValue, destValue, remainingDepth - 1);   
    }
}

请注意,属性枚举只需要一次,因为对象(正如您在评论部分自己所说的那样)属于同一类型。

另外,当性能很重要时,请注意反射。