кто-нибудь сталкивался с любым сценарием, в котором вам нужно было объединить один объект с другим объектом того же типа, объединяя полный граф объектов.
например, Если у меня есть объект person, а один объект person имеет имя, а другое - фамилию, это может привести к объединению обоих объектов в один объект.
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;
}
}
Тем не менее, это работает, когда свойство source имеет значение null, если у target оно есть, оно скопирует его в источник.
ИТ все еще можно улучшить, чтобы объединить, когда есть несоответствия, например if FirstName = "Tiju" и FirstName = "John"
Любые комментарии приветствуются.
Спасибо
TJ