簡體   English   中英

比較不同類型的盒裝值

[英]Comparing boxed values of different types

在 C# 中,值類型可以被裝箱,這會導致某些比較問題,特別是對於不同類型。 示例: 2m == 2L返回true ,但(object)2m == (object)2L返回false 我的問題是:是否可以編寫一個比較方法來獲取兩個對象(裝箱值)參數並在示例案例中返回true 它必須適用於任何值類型組合,並且如果值未裝箱則具有與==運算符相同的行為。 謝謝!

我建議為該任務使用dynamic

object o1 = 2m;
object o2 = 2L;

if ((dynamic)o1 == (dynamic)o2) { Console.WriteLine("Works like charm"); }

然而,我並不完全了解dynamic關鍵字的所有含義,所以要小心!

我認為使用動態是最好的方法,其他解決方案可能是這樣的(馬歇爾總是轉換為更大的類型)

private static bool compareObj(object obj1, object obj2)
{
    bool flag = true;
    try
    {
        object result = Convert.ChangeType(obj1, obj2.GetType());
        object result2 = Convert.ChangeType(obj2, obj1.GetType());
        var first = Marshal.SizeOf(obj1.GetType());
        var second = Marshal.SizeOf(obj2.GetType());
        if (first > second)
        {
             flag = obj1.Equals(result2);
        }
        else
        {
             flag = obj2.Equals(result);
        }
    }
    catch (InvalidCastException ex)
    {
        flag = false;
    }

    return flag;
}

由於接受的dynamic解決方案在找不到合適的==運算符時可能會拋出異常(請參閱我關於比較3UL3L值的評論),因此我實現了另一種檢查相等性的方法。

如果兩個裝箱值的類型相同,或者嘗試通過拆箱與通用類型來比較這些值,則下面的代碼將調用Equals方法。 floatdouble類型有特殊處理,其余 integer 類型通過轉換為decimal進行比較。

這種方法比公認的解決方案慢一點,但它處理的情況更多,從內存分配的角度來看性能更好:

|          Method |      Mean |    Error |   StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------- |----------:|---------:|---------:|-------:|------:|------:|----------:|
| AreEqualDynamic |  83.31 ns | 1.447 ns | 1.354 ns | 0.0172 |     - |     - |      72 B |
| AreEqualConvert | 112.44 ns | 1.156 ns | 0.902 ns |      - |     - |     - |         - |

AreEqualConvert方法實現:

public bool AreEqualConvert(object o1, object o2)
{
    if (ReferenceEquals(o1, o2))
    {
        return true;
    }

    if (o1 is null || o2 is null)
    {
        return false;
    }

    if (o1.GetType() == o2.GetType())
    {
        return o1.Equals(o2);
    }

    switch (o1)
    {
        case float f1:
            switch (o2)
            {
                case double d2:
                    return f1 == d2;
                case IConvertible c2:
                    return f1 == c2.ToSingle(null);
                default:
                    return false;
            }

        case double d1:
            return o2 is IConvertible conv2
                ? d1 == conv2.ToDouble(null)
                : false;

        case IConvertible c1:
            switch (o2)
            {
                case float f2:
                    return c1.ToSingle(null) == f2;
                case double d2:
                    return c1.ToDouble(null) == d2;
                case IConvertible c2:
                    return c1.ToDecimal(null) == c2.ToDecimal(null);
                default:
                    return false;
            }

        default:
            return false;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM