计算对象的变更集

时间:2013-04-05 10:55:27

标签: c# generics windows-store-apps generic-list generic-programming

我正在编写一个Windows应用程序,它从服务器接收一个对象(我创建的自定义类型),让用户编辑该对象,然后将“changeset”提交回服务器。此变更集只是与接收对象类型相同的对象,除了用户编辑的字段外,每个字段都设置为null。然后,这些字段包含用户的编辑,如下所示:

Original Case:
    Description: "Cracked exhaust pipe"
    Status: "Open"
    Customer: ""
    Mileage: 10000

Edited Case:
    Description: ""
    Status "Open"
    Customer: "Example inc."
    Mileage: 10000

Case changeset:
    Description: ""
    Status: null
    Customer: "Example inc."
    Mileage: null

当应用程序首次从服务器下载对象时,我会复制它以供以后比较。然后,用户对其中一个对象进行更改,当用户提交更改时,将使用通用方法CalculateChangeSet计算这两个对象的更改集。它遍历两个对象的每个属性,并将它们进行相等性比较:

public static T CalculateChangeSet<T>(T oldObject, T newObject) where T : new()
{
    T changeSet = (T)Activator.CreateInstance(oldObject.GetType());

    foreach (PropertyInfo property in oldObject.GetType().GetRuntimeProperties())
    {
        var oldValue = property.GetValue(oldObject);
        var newValue = newObject.GetType().GetRuntimeProperty(property.Name).GetValue(newObject);
        if (oldValue != null && newValue != null)
        {
            if (oldValue is IList)
            {
                Type listType = oldValue.GetType().GetRuntimeProperty("Item").PropertyType;

                IList<listType> oldList = (IList<listType>)oldValue; //Visual studio complains about
                IList<listType> newList = (IList<listType>)newValue; //listType not being found

                if (!oldList.SequenceEqual(newList))
                {
                    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null);
                }
            }
            else
            {
                if (!oldValue.Equals(newValue))
                {
                    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, CalculateChangeSet(oldValue, newValue));
                }
            }
        }
        else
        {
            changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue);
        }
    }

    return changeSet;
}

该方法适用于我遇到的每个属性,除了列表,所以我创建了if子句来处理列表。由于list1.Equals(list2)不会比较列表中的项目,因此我们需要将oldValuenewValue投射到List<T>才能使用list.SequenceEqual()

当我尝试使用The type or namespace name 'listType' could not be found (are you missing a using directive or an assembly reference?)创建新列表时,为什么会收到错误说{{1}}?如果有更好的方法来解决这个问题,我愿意接受建议......

1 个答案:

答案 0 :(得分:0)

试试这个:

IList oldList = (IList)oldValue; //Visual studio complains about
IList newList = (IList)newValue; //listType not being found

if (!NonGenericSequenceEqual(oldList, newList))
{
    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null);
}

public static bool NonGenericSequenceEqual(IList a, IList b)
{
    if (ReferenceEquals(a, b))
    {
        return true;
    }
    else if (a == null || b == null)
    {
        return false;
    }
    else
    {
        int count = a.Count;

        if (count != b.Count)
        {
            return false;
        }
        else
        {
            for (int i = 0; i < count; i++)
            {
                if (!Object.Equals(a[i], b[i]))
                {
                    return false;
                }
            }

            return true;
        }
    }
}

弱代码是'Object.Equals(a [i],b [i])'

通过反思的另一种变体:

if (!(bool)typeof(System.Linq.Enumerable).GetMethod("SequenceEqual").MakeGenericMethod(oldValue.GetType().GetRuntimeProperty("Item").PropertyType).Invoke(null, new object[] { oldObject, newObject }))
{
    changeSet.GetType().GetRuntimeProperty(property.Name).SetValue(changeSet, newValue, null);
}