【发布时间】:2010-06-16 09:08:54
【问题描述】:
有没有人遇到过需要将一个对象与另一个相同类型的对象合并的情况,从而合并完整的对象图。 例如如果我有一个人对象并且一个人对象有名字和另一个姓氏,则可以通过某种方式将两个对象合并为一个对象。
public class Person
{
public Int32 Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class MyClass
{
//both instances refer to the same person, probably coming from different sources
Person obj1 = new Person(); obj1.Id=1; obj1.FirstName = "Tiju";
Person obj2 = new Person(); ojb2.Id=1; obj2.LastName = "John";
//some way of merging both the object
obj1.MergeObject(obj2); //??
//obj1.Id // = 1
//obj1.FirstName // = "Tiju"
//obj1.LastName // = "John"
}
我遇到过这种类型的需求,我写了一个扩展方法来做同样的事情。
public static class ExtensionMethods
{
private const string Key = "Id";
public static IList MergeList(this IList source, IList target)
{
Dictionary itemData = new Dictionary();
//fill the dictionary for existing list
string temp = null;
foreach (object item in source)
{
temp = GetKeyOfRecord(item);
if (!String.IsNullOrEmpty(temp))
itemData[temp] = item;
}
//if the same id exists, merge the object, otherwise add to the existing list.
foreach (object item in target)
{
temp = GetKeyOfRecord(item);
if (!String.IsNullOrEmpty(temp) && itemData.ContainsKey(temp))
itemData[temp].MergeObject(item);
else
source.Add(item);
}
return source;
}
private static string GetKeyOfRecord(object o)
{
string keyValue = null;
Type pointType = o.GetType();
if (pointType != null)
foreach (PropertyInfo propertyItem in pointType.GetProperties())
{
if (propertyItem.Name == Key)
{ keyValue = (string)propertyItem.GetValue(o, null); }
}
return keyValue;
}
public static object MergeObject(this object source, object target)
{
if (source != null && target != null)
{
Type typeSource = source.GetType();
Type typeTarget = target.GetType();
//if both types are same, try to merge
if (typeSource != null && typeTarget != null && typeSource.FullName == typeTarget.FullName)
if (typeSource.IsClass && !typeSource.Namespace.Equals("System", StringComparison.InvariantCulture))
{
PropertyInfo[] propertyList = typeSource.GetProperties();
for (int index = 0; index < propertyList.Length; index++)
{
Type tempPropertySourceValueType = null;
object tempPropertySourceValue = null;
Type tempPropertyTargetValueType = null;
object tempPropertyTargetValue = null;
//get rid of indexers
if (propertyList[index].GetIndexParameters().Length == 0)
{
tempPropertySourceValue = propertyList[index].GetValue(source, null);
tempPropertyTargetValue = propertyList[index].GetValue(target, null);
}
if (tempPropertySourceValue != null)
tempPropertySourceValueType = tempPropertySourceValue.GetType();
if (tempPropertyTargetValue != null)
tempPropertyTargetValueType = tempPropertyTargetValue.GetType();
//if the property is a list
IList ilistSource = tempPropertySourceValue as IList;
IList ilistTarget = tempPropertyTargetValue as IList;
if (ilistSource != null || ilistTarget != null)
{
if (ilistSource != null)
ilistSource.MergeList(ilistTarget);
else
propertyList[index].SetValue(source, ilistTarget, null);
}
//if the property is a Dto
else if (tempPropertySourceValue != null || tempPropertyTargetValue != null)
{
if (tempPropertySourceValue != null)
tempPropertySourceValue.MergeObject(tempPropertyTargetValue);
else
propertyList[index].SetValue(source, tempPropertyTargetValue, null);
}
}
}
}
return source;
}
}
但是,这在源属性为空时有效,如果目标有它,它会将其复制到源。 当存在不一致时,仍然可以改进 IT 以合并,例如如果 FirstName="Tiju" 和 FirstName="John"
任何意见表示赞赏。
谢谢 TJ
【问题讨论】:
-
我不明白你的问题是什么。您想要 cmets 如何改进您的代码吗?还是代码有问题?
-
我的问题是,有没有其他人面临这样的要求,他们想出了什么想法。
-
我创建了一个名为 MergeO 的库,它以可定制的通用方式完成此任务。 github.com/diskjunky/mergeo。它比您的实现更复杂,因为为了进行完整的深度合并,任何合并操作都可能需要根对象的上下文(例如,如果
PersonID > 2或其他深奥规则,则选择较新的一个)。
标签: .net reflection object merge graph