仅从一个对象复制尚未填充到相同类型的另一个对象中的填充值
本文关键字:一个对象 填充 同类型 复制 | 更新日期: 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);
}
}
请注意,属性枚举只需要一次,因为对象(正如您在评论部分自己所说的那样)属于同一类型。
另外,当性能很重要时,请注意反射。