== and != operators as well as Equals method seem to not always work on value types.

ScottHellewellScottHellewell USMember, University

It is really weird. My code is doing a lot of reflection to generate the values that do not work properly. This is in iOS, but may be present in android as well.

I am building a Xaml implementation in a portable class library. I parse the Xaml and generate the appropriate instances. Where I seem to be running into the biggest problems are with my bindings. I do a comparison something like so:

        var sourceValue = SourcePropertyInfo.GetValue(Source);
        var targetValue = TargetPropertyInfo.GetValue(Target);
        if (sourceValue != targetValue)
            SourcePropertyInfo.SetValue(Source, TargetPropertyInfo.GetValue(Target));

I haven't experienced the problem on any classes (reference types), but have experienced it on enums, doubles, and structs (value types).

An example with an enum doing it was my implementation of HorizontalAlignment. Both sourceValue and targetValue were equal to HorizontalAlignment.Left, but the != operator returned false, I also tested the other various operators. Casting sourceValue and target value to HorizontalAlignment seemed to solve it as well as casting them to int.

With structs, I found that it would not utilize my implementations of the ==, !=, Equals, and GetHashCode. My Thickness struct had this problem. I put breakpoints on my implementations of ==, etc. and they were never hit. Converting it from a struct to a class and everything worked.

With doubles, this is occurring when comparing double.NaN.
image

Some of the time it appears that these problems only seem to happen when debugging as well. For example the issue with double.NaN above seems to not happen when running without debugging.

Does anyone have any ideas?

Thanks

Scott HEllewell

Posts

  • DaveHuntDaveHunt USMember ✭✭✭✭✭

    Best guess:

    GetValue() returns an Object reference regardless of the type of the value.

    Your class comparisons work because the it performs a reference comparison. If both object variables reference the same object, then they're equal.

    Your value type comparisons don't work because they have to be boxed to return an Object reference. Thus, they each get their own new Object reference and are now not equal in a reference comparison.

    Casting the Object references to the actual value type works because the comparison becomes a value comparison instead of a reference comparison.

    So it seems to be working exactly as it should.

  • GuillermoGutierrezGuillermoGutierrez ESMember ✭✭✭

    Double.NaN is not equal to itself.

    More info in this SO question.

    Also, you shouldn't compare double equality, but using a delta:

    const double tolerance = 0.00001;
    Math.Abs(double1 - double2) <= tolerance
    

    More info here.

  • ScottHellewellScottHellewell USMember, University

    @GuillermoGutierrez

    That is interesting, can you explain then why my unit test I created didn't fail:

    Assert.AreEqual(double.NaN, double.NaN);

    My guess is that Assert.AreEqual must not use the double.NaN .Equals(), ==, or != method/operators.

    Sure enough, decompiling Assert.AreEquals, and I find special handling for .Nan.

    OK, the double one seems to be good.

    @DaveHunt
    My unit test:

            object value1 = HorizontalAlignment.Left;
            object value2 = HorizontalAlignment.Left;
            Assert.AreEqual(value1, value2);
    

    doesn't fail either.

    My Type converter is basically doing the following and it doesn't fail either:

            object value1 = Enum.Parse(typeof(HorizontalAlignment), "Left");
            object value2 = Enum.Parse(typeof(HorizontalAlignment), "Left");
            Assert.AreEqual(value1, value2);
    

    The structs also do not have a problem in my unit test.

            object value1 = new Thickness(1, 1, 1, 1);
            object value2 = new Thickness(1, 1, 1, 1);
            Assert.AreEqual(value1, value2);
    

    The unit tests are running on the Microsoft framework and not the Xamarin IOS framework.

    Fun stuff, I have work arounds for them all so far, but it seems like maybe there is a bug somewhere on some of this.

Sign In or Register to comment.