簡體   English   中英

C#IF語句給出錯誤結果

[英]C# IF statement gives incorrect result

我似乎偶然發現了C#IF語句給出錯誤結果的情況。 我試圖編寫一個Equals()版本來深比較一個類的兩個實例。

這是一個帶有一些調試的簡單測試用例:

namespace IfTest
{
class MyClass
{
    public string String1
    { get; set; }
    public int Int1
    { get; set; }
    public float Float1
    { get; set; }
    public bool Bool1
    { get; set; }

    public MyClass(string s, int i, float f, bool b)
    {
        String1 = s;
        Int1 = i;
        Float1 = f;
        Bool1 = b;
    }

    public override bool Equals(object otherInstance)
    {
        bool isEqual = true;
        MyClass other = (MyClass)otherInstance;
        int good = 0, bad = 0;

        // Compare everything in 'other' to 'this', using reflection
        Type sourceType = other.GetType();
        Type destinationType = this.GetType();

        foreach (PropertyInfo sourceProperty in sourceType.GetProperties())
        {
            PropertyInfo destinationProperty = destinationType.GetProperty(sourceProperty.Name);
            if (destinationProperty == null)
            {
                Console.WriteLine("Destination {0} is null", sourceProperty.Name);
                isEqual = false;
                bad++;
            }
            else
            {
                var x = sourceProperty.GetValue(other);
                var y = destinationProperty.GetValue(this);
                //if (sourceProperty.GetValue(other, null) != destinationProperty.GetValue(this, null))

                if (x != y)
                {
                    Console.WriteLine("Name {0}: {1} {2} different", sourceProperty.Name, x, y);
                    isEqual = false;
                    bad++;
                }
                else
                {
                    Console.WriteLine("Name {0}: {1} {2} same", sourceProperty.Name, x, y);
                    good++;
                }
            }
        }

        Console.WriteLine("Good: {0}. Bad {1}", good, bad);
        return isEqual;
    }
}
}


using System;

namespace IfTest
{
class Program
{
    static void Main(string[] args)
    {
        MyClass a = new MyClass("abc", 23, 45.67F, false);
        MyClass b = new MyClass("abc", 23, 45.67F, false);

        // Test IF usually works with var's
        var i = a.Int1;
        var j = b.Int1;
        Console.WriteLine("Main test {0}",
            (i == j) ? "OK" : "Fail");

        a.Equals(b);

        Console.ReadLine();
    }

}
}

在MyClass.Equals()中,我已注釋掉if (sourceProperty.GetValue(other, null) != destinationProperty.GetValue(this, null))

並將2個屬性值放入臨時變量中。

運行此命令可獲得:

Main test OK
Name String1: abc abc same
Name Int1: 23 23 different
Name Float1: 45.67 45.67 different
Name Bool1: False False different
Good: 1. Bad 3

這表明IF對於數字類型失敗。 如果將x和y分配更改為: var x = sourceProperty.GetValue(other); var y = sourceProperty.GetValue(other);

我可以通過添加以下內容來解決它:

if (x is int)
{
    if ((int) x == (int)y)
        Console.WriteLine("INT Name {0}: {1} {2} same", sourceProperty.Name, x, y);
}

但我必須測試每種數字類型。

這是C#問題還是我做錯了什么? 我正在使用Visual Studio Express 2013 for Desktop版本12.0.31101.00更新4,.Net版本4.5.50938和Visual C#2013。

比較失敗,因為您在Object類型上使用==運算符-執行引用相等操作而不是值相等操作,此外,.NET Framework中的反射API不會緩存並返回預先生成的反射對象實例,這就是為什么它返回false的原因:

foo.GetType().GetMethod("Bar") == foo.GetType().GetMethod("Bar")

另一個問題是您不恰當地使用var關鍵字:它隱藏了您對值類型進行裝箱的事實。 xy的類型是Boxed- int作為Object ,因此為什么要執行引用相等比較而不是值相等。

解決方案是顯式調用引用類型的.Equals方法,並通過強制轉換為實型來取消對值類型的裝箱:

foo.GetType().GetMethod("Bar").Equals( foo.GetType().GetMethod("Bar") )

Int32 x = (Int32)sourceProperty.GetValue(other);

調用GetValue ,您將獲得一個object 當值為int ,將該int裝箱為object然后返回。 現在,當您使用==比較兩個裝箱的整數時 ,將使用object類中的==運算符。 當您轉換為int ,它現在使用int==運算符。 正如您所發現的,它們可以做兩種不同的事情。

這將返回false:

Console.WriteLine("{0}", (object)5 == (object)5);

返回true:

Console.WriteLine("{0}", ((object)5).Equals((object)5));

您可以使用.Equals()方法進行相等性檢查。

如果您知道要比較的內容,則結果有意義。

如果您指定變量類型而不使用var關鍵字,您將知道變量是對象:

object x = sourceProperty.GetValue(other);
object y = destinationProperty.GetValue(this);

無論使用反射讀取的屬性的類型是什么, GetValue方法的返回值都是object

對於引用類型,變量值將作為引用。 對於值類型,變量值將是對該值所在的對象的引用。

對於引用類型,比較有效,因為變量直接指向對象。 對於字符串,將找到並使用String.Equals方法。 對於值類型,裝箱值的對象沒有該值的相等比較器,因此將使用Object.Equals方法,該方法將對對象的引用而不是對象中的值進行比較。

這可以用一個更簡單的示例顯示:

object x = 1;
object y = 1;
Console.WriteLine(x == y);

輸出:

False

即使對象包含相同的裝箱值,但由於引用不同,比較也會返回false

您的代碼是錯誤的,因為GetValue返回一個對象,因此返回了兩個不同的對象

https://msdn.microsoft.com/zh-CN/library/b05d59ty%28v=vs.110%29.aspx

您必須先獲取GetValue,然后將其強制轉換(如果可以)並比較兩者(這將是值類型)

暫無
暫無

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

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