C#IF语句给出的结果不正确

C#IF语句给出的结果不正确,c#,C#,我似乎偶然发现了一种情况,即C#IF语句给出了错误的结果。我试图编写Equals()的一个版本来深入比较一个类的两个实例 下面是一个带有一些调试的简单测试用例: namespace IfTest { class MyClass { public string String1 { get; set; } public int Int1 { get; set; } public float Float1 { get; set; } public

我似乎偶然发现了一种情况,即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))

并将这两个属性值放入临时变量中

运行此命令将提供:

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(其他)
var y=sourceProperty.GetValue(其他)

我可以通过添加以下内容来解决此问题:

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用于桌面版本12.0.31101.00更新4、.Net版本4.5.50938和Visual C#2013。

比较失败,因为您在
对象
类型上使用了
=
运算符,该类型执行引用相等操作,而不是值相等操作,此外,.NET Framework中的反射API不会缓存和重新返回预生成的反射对象实例,这就是为什么返回false的原因:

foo.GetType().GetMethod("Bar") == foo.GetType().GetMethod("Bar")
Console.WriteLine("{0}", (object)5 == (object)5);
另一个问题是您不恰当地使用了
var
关键字:它隐藏了您正在装箱值类型的事实。
x
y
的类型是装箱的-
int
作为
对象
,因此它执行引用相等比较而不是值相等

解决方案是显式调用引用类型上的
.Equals
方法,并通过强制转换为实际类型取消装箱值类型:

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

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

比较失败是因为您在
对象
类型上使用了
=
运算符-它执行引用相等操作而不是值相等操作,而且.NET Framework中的反射API不会缓存并重新返回预生成的反射对象实例,这就是为什么返回false:

foo.GetType().GetMethod("Bar") == foo.GetType().GetMethod("Bar")
Console.WriteLine("{0}", (object)5 == (object)5);
另一个问题是您不恰当地使用了
var
关键字:它隐藏了您正在装箱值类型的事实。
x
y
的类型是装箱的-
int
作为
对象
,因此它执行引用相等比较而不是值相等

解决方案是显式调用引用类型上的
.Equals
方法,并通过强制转换为实际类型取消装箱值类型:

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

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

您的代码是错误的,因为GetValue返回一个对象,因此返回两个不同的对象


您必须首先获取值,然后将其强制转换为casetable,并比较两者(这将是值类型)

您的代码是错误的,因为GetValue返回一个对象,因此返回两个不同的对象


您必须首先获取值,然后将其强制转换为casetable,并比较两者(这将是值类型)

当您调用
GetValue
时,您将得到一个
对象。当值为
int
时,该
int
将作为
对象装箱,然后返回。现在,当您使用
=
比较两个装箱整数时,将使用
对象
类中的
=
运算符。当您强制转换到
int
时,它现在正在使用
int
中的
=
操作符。正如你所发现的,它们做两件不同的事情

这将返回false:

foo.GetType().GetMethod("Bar") == foo.GetType().GetMethod("Bar")
Console.WriteLine("{0}", (object)5 == (object)5);
这将返回true:

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

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

当您调用
GetValue
时,您将返回一个
对象。当值为
int
时,该
int
将作为
对象装箱,然后返回。现在,当您使用
=
比较两个装箱整数时,将使用
对象
类中的
=
运算符。当您强制转换到
int
时,它现在正在使用
int
中的
=
操作符。正如你所发现的,它们做两件不同的事情

这将返回false:

foo.GetType().GetMethod("Bar") == foo.GetType().GetMethod("Bar")
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

如果您知道要比较的内容,则结果是有意义的

如果您指定变量类型而不是使用
var
关键字,您将知道变量是对象:

object x = sourceProperty.GetValue(other);
object y = destinationProperty.GetValue(this);
无论您使用反射读取的属性类型是什么,
GetValue
方法的返回值都是
object

对于引用类型,变量值将作为引用。对于值类型,变量值将是对v