我要求从一个对象中复制仅填充的值,这些对象尚未填充在同一类型的另一个对象中。
例如,我们传递了一个对象,它只是部分地用数据实例化,我们读取数据库以获得对象的完全实例化版本 - 但是这可能没有由提交到数据库的应用程序进行更改 - 因此我们需要将数据库版本中的任何值移动到对象的传入版本中 - 而不会覆盖传入对象中可能已存在的任何值(因为这些是最新的值)。
Adam Robinson在另一篇文章中提出的以下代码(见下文非常有用 - 谢谢!)是一个很好的起点。但是我需要扩展它 - 因为我只想复制目标对象上尚未填充的值(即需要检查destProperty不为null)。然而,作为一个额外的复杂性,在传入的对象中声明了内部复杂类型,此代码复制高级子组而不进入子组的各个属性(即使用Root cdt声明的任何变量我可以尝试和检查是否为null,但是只需复制子cdts中的所有字段而不通过各个字段。)
非常感谢任何帮助。
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;
}
}
}
}
答案 0 :(得分:0)
首先,您需要确定书中填充的含义。
确定后,请编写以下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);
}
}
请注意,只需要一次属性枚举,因为对象(正如您在评论部分中所说的那样)属于同一类型。
当表现很重要时,请注意反思。