.net - 合并 .net 对象图

标签 .net reflection object merge graph

有没有人遇到过需要将一个对象与另一个相同类型的对象合并,从而合并完整的对象图的场景。 例如如果我有一个人对象,一个人对象有名字,另一个有姓氏,可以通过某种方式将这两个对象合并为一个对象。

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"

感谢任何评论。

谢谢 田杰

最佳答案

您的代码看起来很讨厌。您确定需要这样的通用模型吗?您打算单独合并多个 Person 对象吗?如果是这样,合并要求是否完全相同?如果您需要合并其他类型,更改是它们必须以不同的方式合并。也许你应该选择没有反射的设计。这是另一个想法:

public interface IMergable<T>
{
    T MergeWith(T other);
}

public interface IEntity
{
    object EntityId { get; }
}

public class Person : IMergable<Person>, IEntity
{
    public int Id { get; set; }

    object IEntity.EntityId { get { return this.Id; } }

    public Person MergeWith(Person other)
    {
        var mergedperson = new Person();

        // Do merging here, and throw InvalidOperationException
        // when objects  can not be merged.

        return mergedPerson;
    }
}

你的扩展方法看起来像这样:

public static IEnumerable<T> MergeList<T>(this IEnumerable<T> left,
    IEnumerable<T> right)
    where T : IMergable<T>, IEntity
{
    return
       from leftEntity in left
       from rightEntity in right
       where leftEntity.EntityId.Equals(rightEntity.EntityId)
       select leftEntity.MergeWith(rightEntity);
}

关于.net - 合并 .net 对象图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3051948/

相关文章:

asp.net - 如何强制编译 ASP.NET MVC View ?

c# - 获取 AppDomain.CurrentDomain 中所有用户创建的类

python-3.x - 去命名参数

python - 为什么 Python 对象中的 `self` 是不可变的?

.net - 如何使用iTextSharp将PDF与可填写的表单字段合并/合并?

c# - 区分用户关闭表单和用户关闭应用程序

c# - 命名空间不附加到 WCF 中的 bool,除非不同于类的命名空间

go - 调用方法属于struct的字段

Python 在特定条件下停止嗅探

arrays - Redis reJson : JSON. ARRAYAPPEND 返回 WRONGTYPE 针对持有错误类型值的键的操作