简体   繁体   English

比较C#中的(特定)对象属性

[英]Comparing (specific) object properties in c#

Building upon this answer for comparing objects in C# Comparing object properties in c# 答案的基础上比较C#中的对象比较C#中的对象属性

Knowing this is a complex topic, I wanted to handle a few more specific structures. 知道这是一个复杂的主题,我想处理一些更具体的结构。

While this code will match properties if they are simple value types such as this object: 虽然此代码将匹配属性(如果它们是简单的值类型),例如此对象:

public class BasicStuff
{
    public int anInt { get; set; }
    public bool aBool { get; set; }
}

But as soon as it gets any more complex, this code fails. 但是,一旦变得更加复杂,此代码就会失败。

So what I would like to do is make it a bit more usable for nested objects of the above, such as: 所以我想做的是使它对于上述嵌套对象更加有用,例如:

public class NestedStuff
{
    public BasicStuff theBasic { get; set; }
}

Any array of the above, such as: 上面的任何数组,例如:

public class ArrayStuff
{
    public BasicStuff[] theBasicArray { get; set; }
}

And finally any combination of the above: 最后是以上的任意组合:

public class AllTheStuff
{
    public int anInt { get; set; }
    public bool aBool { get; set; }
    public BasicStuff theBasic { get; set; }
    public BasicStuff[] theBasicArray { get; set; }
}

So what I came up with was the following: 因此,我想到了以下内容:

    public static bool AllPublicPropertiesEqual<T>(T AObj, T BObj, params string[] ignore) where T : class
    {
        if (AObj != null && BObj != null)
        {
            Type type = typeof(T);
            List<string> ignoreList = new List<string>(ignore);
            foreach (PropertyInfo pInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (!ignoreList.Contains(pInfo.Name))
                {
                    if (pInfo.PropertyType.IsArray)
                    {
                        object AValue = type.GetProperty(pInfo.Name).GetValue(AObj, null);
                        object BValue = type.GetProperty(pInfo.Name).GetValue(BObj, null);
                        string t = AValue.GetType().ToString();

                        if (!AllPublicPropertiesEqual<object>(AValue, BValue))
                            return false;
                    }
                    else if (!pInfo.PropertyType.IsValueType && !pInfo.PropertyType.IsPrimitive && !pInfo.PropertyType.IsEnum && pInfo.PropertyType != typeof(string)) 
                    //else if (Convert.GetTypeCode(pInfo.PropertyType) == TypeCode.Object)
                    {
                        object AValue = type.GetProperty(pInfo.Name).GetValue(AObj, null);
                        object BValue = type.GetProperty(pInfo.Name).GetValue(BObj, null);

                        if (!AllPublicPropertiesEqual<object>(BValue, AValue))
                            return false;
                    }
                    else
                    {
                        object selfValue = type.GetProperty(pInfo.Name).GetValue(AObj, null);
                        object toValue = type.GetProperty(pInfo.Name).GetValue(BObj, null);

                        if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)))
                            return false;
                    }
                }
            }
            return true;
        }
        return AObj == BObj;
    }

Only this fails because when recursively calling AllPublicPropertiesEqual, I need to pass the specific values type rather than just a generic object type. 只有这样才能失败,因为当递归调用AllPublicPropertiesEqual时,我需要传递特定的值类型,而不仅仅是普通的对象类型。 But I dont know how to do this.... Any ideas are greatly appreciated... 但是我不知道该怎么做。

Your method does not have to be generic. 您的方法不必是通用的。 You can change the beginning of the method to: 您可以将方法的开头更改为:

public static bool AllPublicPropertiesEqual(object AObj, object BObj, params string[] ignore) 
{
    if (AObj != null && BObj != null)
    {
        Type type = AObj.GetType();

        if (BObj.GetType() != type)
            throw new Exception("Objects should be of the same type");

        ....
    }

    ....
}

Well first thing what is that you should create Interface for those classes because from what I see you can combine those classes but all of them will have the same properties. 首先,您应该为这些类创建接口是什么,因为从我的角度来看,您可以组合这些类,但是它们都将具有相同的属性。 Second option is create some Base abstract class with those properties and inherit from it. 第二种选择是使用这些属性创建一些基本抽象类并从中继承。 It is up to you what you choose. 您的选择取决于您。 Than create in this Base class or Interface Equals functions where you will equal directly the shared properties it is much easier and I think more efficient :-) 比在此Base类或Interface Equals函数中创建直接与共享属性相等的方法要容易得多,我认为效率更高:-)

public abstract class BaseStaff {
  public int anInt { get; set; }
  public bool aBool { get; set; }
  public abstract bool Equals(BaseStaff anotherStaff);
}

Then you can use this class and create your BasicStaff class and AllTheStaff class too in BasicStaff implement Equals method like this. 然后,您可以使用此类在BasicStaff实现Equals方法中创建BasicStaff类和AllTheStaff类。

public override bool Equals(BaseStaff staff) {
   this.anInt == staff.anInt &&
   this.aBool == staff.aBool;
}

In AllTheStaff u can than override this method like this 在AllTheStaff中,您可以像这样重写此方法

public override bool Equals(BaseStaff staff) {
  bool baseEquals = base.Equals(staff);
  bool basicStaffEquals = this.BasicStaff.Equals(staff);
  return baseEquals || basicStaffEquals;    
}

This is just core idea and maybe I dont understand you well what you really want to achieve but hope it helps you :) 这只是核心思想,也许我不太了解您真正想要实现的目标,但希望它能对您有所帮助:)

tested Solution 经过测试的解决方案

        public static bool AllPublicPropertiesEqual<T>(T AObj, T BObj, params string[] ignore) where T : class
    {
        if (AObj != null && BObj != null)
        {
            Type type = typeof(T);
            List<string> ignoreList = new List<string>(ignore);
            foreach (PropertyInfo pInfo in type.GetCType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (!ignoreList.Contains(pInfo.Name))
                {
                    if (pInfo.PropertyType.IsArray)
                    {
                        object aElementValues = (type.GetProperty(pInfo.Name).GetValue(AObj, null));
                        object bElementValues = (type.GetProperty(pInfo.Name).GetValue(BObj, null));

                        if (aElementValues != null && bElementValues != null)
                        {
                            List<object> AListValues = new List<object>();
                            List<object> BListValues = new List<object>();

                            foreach (var v in (IEnumerable)aElementValues)
                                AListValues.Add(v);

                            foreach (var v in (IEnumerable)bElementValues)
                                BListValues.Add(v);

                            if (AListValues.Count == BListValues.Count)
                            {
                                object[] aArray = AListValues.ToArray();
                                object[] bArray = BListValues.ToArray();

                                for (int i = 0; i < aArray.Length; i++)
                                {
                                    if (!AllPublicPropertiesEqual(aArray[i], bArray[i]))
                                        return false;
                                }
                            }
                            else
                                return false;
                        }
                        else if ((aElementValues == null) != (bElementValues == null))
                            return false;
                    }
                    else if (!pInfo.PropertyType.IsValueType && !pInfo.PropertyType.IsPrimitive && !pInfo.PropertyType.IsEnum && pInfo.PropertyType != typeof(string))
                    //else if (Convert.GetTypeCode(pInfo.PropertyType) == TypeCode.Object)
                    {
                        object AObjectValue = type.GetProperty(pInfo.Name).GetValue(AObj, null);
                        object BObjectValue = type.GetProperty(pInfo.Name).GetValue(BObj, null);

                        if (!AllPublicPropertiesEqual(BObjectValue, AObjectValue))
                            return false;
                    }
                    else
                    {
                        object aValue = type.GetProperty(pInfo.Name).GetValue(AObj, null);
                        object bValue = type.GetProperty(pInfo.Name).GetValue(BObj, null);

                        if (aValue != bValue && (aValue == null || !aValue.Equals(bValue)))
                            return false;
                    }
                }
            }
            return true;
        }
        return AObj == BObj;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM