比较2个自定义对象 - C#

时间:2009-04-28 14:02:44

标签: c# .net

我需要在基类中编写一个泛型方法,它接受2个对象作为参数,并将它们进行相等性比较。

例如:

public abstract class BaseData
{

  public bool AreEqual(object O1, object O2)
  {
    //Need to implement this
  }
}

public class DataTypeOne : BaseData
{
  public string Name;
  public string Address;
}

public class DataTypeTwo : BaseData
{
  public int CustId;
  public string CustName;
}

AreEqual()方法可接受DataTypeOne的2个实例或DataTypeTwo的2个实例。

我的猜测是我需要使用反射?我可以使用LINQ,如果它更可读/简洁。

修改: 我想在基类中实现此方法的原因是因为项目限制。有大量的开发人员在派生类上工作。通过在基类中实现这一点,我试图减少一件事让他们担心。

6 个答案:

答案 0 :(得分:13)

(假设您想要的是比较两个对象的所有字段是否相等。)

通常情况下,您不会为此使用反射,您只需自己比较每个字段。为此目的存在IEquatable<T>接口,您也可能希望覆盖有问题类型的Object.Equals()。例如:

public class DataTypeTwo : BaseData, IEquatable<DataTypeTwo>
{
    public int CustId;
    public string CustName;

    public override int GetHashCode()
    {
        return CustId ^ CustName.GetHashCode(); // or whatever
    }

    public override bool Equals(object other)
    {
        return this.Equals(other as DataTypeTwo);
    }

    public bool Equals(DataTypeTwo other)
    {
        return (other != null &&
                other.CustId == this.CustId &&
                other.CustName == this.CustName);
    }
}

另外,请考虑您的类型是否有意义struct。值类型通过逐个字段比较自动比较相等性。

请注意,通过覆盖Equals,您基本上可以实现您尝试使用“master equals方法”方案实现的功能(在我看来)。也就是说,使用DataTypeTwo的人可以自然地测试平等,而无需了解您的API的任何特殊内容 - 他们只会像使用其他内容一样使用Equals

编辑:感谢Jared提醒我GetHashCode。您还希望通过确保任何两个“相等”的对象也返回相同的哈希码来覆盖它以维护哈希表中的正常外观行为。

答案 1 :(得分:4)

这是我用反射想出来的。希望能帮助到你。

public bool AreEqual(object obj)
    {
        bool returnVal = true;

        if (this.GetType() == obj.GetType())
        {
            FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            foreach (FieldInfo field in fields)
            {
                if(field.GetValue(this) != field.GetValue(obj))
                {
                    returnVal = false;
                    break;
                }
            }
        }
        else
            returnVal = false;

        return returnVal;
    }

答案 2 :(得分:2)

不要这样做。继承是最佳方法,每个类都应该覆盖需要的Equal和GetHashCode。

也许你现在可以从这些开发人员那里完成一些工作,但是当产品需要维护时,我会回来咬你的屁股。

说真的,试着找另一种方法来帮助。

答案 3 :(得分:1)

我可能会这样做:

public abstract class BaseData : IEquatable<BaseData>
{
    public abstract bool Equals(BaseData other);
}

public class DataTypeOne : BaseData
{
    public string Name;
    public string Address;

    public override bool Equals(BaseData other)
    {
        var o = other as DataTypeOne;
        if(o == null)
            return false;
        return Name.Equals(o.Name) && Address.Equals(o.Address);
    }
}

public class DataTypeTwo : BaseData
{
    public int CustId;
    public string CustName;

    public override bool Equals(BaseData other)
    {
        var o = other as DataTypeTwo;
        if (o == null)
            return false;
        return CustId == o.CustId && CustName.Equals(o.CustName);
    }
}

答案 4 :(得分:0)

是的,您将不得不使用反射,因为基类对派生类一无所知。但是为什么要在基类中实现该函数?为什么不在派生类中?

此外,还有一种标准方法可以通过重写Object.GetHashCode()和Object.Equals()来实现此目的。

答案 5 :(得分:0)

public void CompareTwoObjects()
{
    try {   
        byte[] btArray = ObjectToByteArray(object1);   //object1 is you custom object1
        byte[] btArray2 = ObjectToByteArray(object2); //object2 is you custom object2
        bool result = ByteArrayCompare(btArray, btArray2);
    } catch (Exception ex) {
        throw ex;
    }
}

public byte[] ObjectToByteArray(object _Object)
{
    try {
        // create new memory stream
        System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream();

        // create new BinaryFormatter
        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter
            = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

        // Serializes an object, or graph of connected objects, to the given stream.
        _BinaryFormatter.Serialize(_MemoryStream, _Object);

        // convert stream to byte array and return
        return _MemoryStream.ToArray();
    } catch (Exception _Exception) {
        // Error
        Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
    }

    // Error occured, return null
    return null;
}

public bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i = 0; i < a1.Length; i++)
        if (a1[i] != a2[i])
            return false;

    return true;
}