【问题标题】:C# compare two objects of unknown types (including reference and value types)C#比较两个未知类型的对象(包括引用和值类型)
【发布时间】:2010-12-02 16:29:44
【问题描述】:

是否可以在 C# 中使用它们的类型比较器来比较两个未知类型的对象(包括引用类型和值类型)?

目标是编写一个具有如下签名的函数:

public bool Compare(object a, object b)
{
     // compare logic goes here
}

哪个会返回

Compare(100d, 100d) == true
Compare(100f, 100f) == true
Compare("hello", "hello") == true
Compare(null, null) == true 
Compare(100d, 101d) == false
Compare(100f, null) == false

// Use type comparators where possible, i.e.:
Compare(new DateTime(2010, 12, 01), new DateTime(2010, 12, 01)) == true
Compare(new DateTime(2010, 12, 01), new DateTime(2010, 12, 02)) == false
Compare(new DateTime(2010, 12, 01), null) == false

是否有一种通用的方法可以解决这个问题,适用于任何类型的对象?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    您可以使用静态object.Equals(object x, object y) 方法,而根本不用费心编写您的方法。这将适当地处理空值,并委托给与xy 相关联的object.Equals(object) 的实现... 不应该 重要,因为Equals 的意思是对称的。

    请注意,此对任何类型使用 == 运算符 - 运算符不能被覆盖,只能重载(这意味着它们是在 编译时选择的 em>,而不是 执行时间。在大多数情况下,Equals 应该做你想做的事情。在某些情况下,即使 Equals 被覆盖,== 也可能不会被重载......但我在我使用过的任何类型中,我从来不知道反过来是正确的。

    请注意,使用这种方法会任何值类型...

    编辑:删除了关于有效重新实现的部分 - 很糟糕 - EqualityComparer<T>.Default。有关更多信息,请参阅 Marc 的答案。当然,如果您不能使用泛型类型,这将无济于事。

    最后一点:我不会调用你的方法Compare。该名称通常与 ordering 值相关联,而不是比较它们是否相等。

    【讨论】:

    • 当然,后者仅适用于引用类型,因为您必须拥有 where T : class 才能使用 v1 == null 以防止值类型比较。
    • 这里有什么不使用EqualityComparer<T>.Default的理由吗?这会让事情变得更普遍(IEquatable<T> 约束不需要),但除非绝对必要,否则不会强制装箱,不是吗?
    • @aqwert:不。对于值类型,它总是评估为 null。
    • @Ani:只是大脑冻结 :) Marc 现在已经在他的回答中涵盖了这一点,所以我已经编辑了我的东西。
    • 有没有办法让它也适用于 int、long 等原始类型。
    【解决方案2】:

    一个合理的选择是使用泛型,即

    public bool Compare<T>(T a, T b) {...}
    

    您无需在代码中指定T,因为编译器通常能够识别它(即您现有的示例将“按原样”工作)

    对于实施:

    bool equal = EqualityComparer<T>.Default.Equals(x, y);
    

    (对于泛型类型T

    实际上我会避免使用 Compare 这个词,因为它在其他地方用来表示 &lt; / == / &gt; - 所以我可能有:

    public static bool Equals<T>(T a, T b) {
        return EqualityComparer<T>.Default.Equals(a, b);
    }
    

    这个:

    • 当 T 是结构时避免装箱
    • 正确处理空值/Nullable&lt;T&gt;
    • 支持IEquatable&lt;T&gt;
    • 或回退到常规Equals

    它确实使用== 运算符,但MiscUtil 有一个Operator通过

    bool equal = Operator.Equal<T>(x,y);
    

    (请注意,如果T 没有== 运算符,则后者将失败,尽管考虑一下,它可以使用EqualityComparer&lt;T&gt;.Default.Equals 作为后备;它只是没有)


    为了完整起见,请注意Comparer&lt;T&gt;.Default.Compare(x,y) 处理比较操作。

    【讨论】:

    • 感谢您的出色回答,您自己和 Jon Skeet 的回答都适用于我的特定用例。
    【解决方案3】:

    object.equals(x, y) 怎么样?这也将接受空值。

    【讨论】:

      【解决方案4】:

      怎么样

      if (a == null && b == null) return true;
      if (a == null && b != null) return false;
      return (a.equals(b));
      

      ?

      【讨论】:

        【解决方案5】:

        我不能 100% 确定这是否适用于所有情况,但请尝试一下

        公共布尔比较(对象a,对象b) { 返回 a.Equals(b); }

        【讨论】:

        • 如果 a 为 null,这将导致 NullReferenceException。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-17
        • 1970-01-01
        • 1970-01-01
        • 2014-06-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多