Let's take a moment and think about exactly how boxed variables work when checking to see if they are equal.

Here is a little Console application to do a quick comparison of how the Equals function and == operator work.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VariableBoxEqualityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int x = 1;
            int y = 1;

            test(x, y);
           
            x = 2;
            y = 3;
            test(x, y);

            x = 5;
            test(x);
            Console.ReadKey();
        }

        private static void test(int x)
        {
            Console.WriteLine();
            Console.WriteLine("Testing with x=y={0}", x);
            DoTests(x, x);
            object ox = x;
            ObjectRefIsEquals(ref ox, ref ox);
            ObjectRefIsEqual(ref ox, ref ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);
        }

        private static void test(int x, int y)
        {
            Console.WriteLine();
            Console.WriteLine("Testing with x={0} and y={1}", x, y);
            DoTests(x, y);
            object ox = x;
            object oy = y;
            ObjectRefIsEquals(ref ox, ref oy);
            ObjectRefIsEqual(ref ox, ref oy);
        }

        private static void DoTests(int x, int y)
        {
            object ox = x;
            object oy = y;
            ObjectIsEqual(ox, oy);
            ObjectIsEquals(ox, oy);
            intIsEqual(x, y);
            intIsEquals(x, y);
        }

        public static void intIsEqual(int x, int y)
        {
            Console.WriteLine("(int)x==(int)y : {0}", x == y);
        }

        public static void intIsEquals(int x, int y)
        {
            Console.WriteLine("((int)x).Equals((int)y) : {0}", x.Equals(y));
        }

        public static void ObjectIsEqual(object x, object y)
        {
            Console.WriteLine("(object)x==(object)y : {0}", x == y);
        }

        public static void ObjectIsEquals(object x, object y)
        {
            Console.WriteLine("((object)x).Equals((object)y) : {0}", x.Equals(y));
        }

        public static void ObjectRefIsEquals(ref object x, ref object y)
        {
            Console.WriteLine("((ref object)x).Equals((ref object)y) : {0}", x.Equals(y));
        }

        public static void ObjectRefIsEqual(ref object x, ref object y)
        {
            Console.WriteLine("((ref object)x)==((ref object)y) : {0}", x==y);
        }
    }
}

Go ahead and run the test, I'll wait....

There are four groups of results, let us about the first result in each set (and the only one in the last set).

(object)x==(object)y : False.  With the exception of the last result this test was always False.  Why?  Because == was checking to see if the object was the same object, not if the values were the same.  In the first 3 sets x and y were boxed into the ox and oy objects before the call to ObjectIsEqual.  The forth set passed ox in twice ObjectIsEqual(ox, ox); .

Even when the values of x and y are the same the act of boxing them makes the objects different, and therefore not equal using the == operator.

If you box the same variable a second time the two objects will not be equal even though they are the same variable. 

Here's a code change you can use to easily test that if you like...

 private static void test(int x)
        {
            Console.WriteLine();
            Console.WriteLine("Testing with x=y={0}", x);
            DoTests(x, x);
            object ox = x;
            ObjectRefIsEquals(ref ox, ref ox);
            ObjectRefIsEqual(ref ox, ref ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);

            Console.WriteLine();
            object oy = x;
            ObjectIsEqual(ox, oy);
        }

the 2nd test in in set is the ((object)x).Equals((object)y) test.  It passed in the 1st and 3rd set while failing in the 2nd.  Which is what we would expect since 1=1, 2!=3 and 5=5.  So the Equals function on a boxed (or unboxed) int works.

The 3rd and 4thtests in each set  are the same functions from the first two tests except on unboxed ints.  Both the == operator and the Equals method were correct in little tests. (If they were Id be worried).

the 5th and 6th test in each set are the same as the first two expect we are passing the objects in by reference.  We would expect the same results...but no, the in the 3rd set (object)x==(object y) was false and ref object x==ref object y was true.... what happened?

The 1st test boxes x twice and passes it into the test. So the objects are not the same and it fails.

The 6th test boxes x once and pass in the same object twice so they match.  It has nothing to do with them being passed as a ref.   Here's another code snip you can use to test it.

private static void test(int x)
        {
            Console.WriteLine();
            Console.WriteLine("Testing with x=y={0}", x);
            DoTests(x, x);
            object ox = x;
            ObjectRefIsEquals(ref ox, ref ox);
            ObjectRefIsEqual(ref ox, ref ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);

            Console.WriteLine();
            object oy = x;
            ObjectIsEqual(ox, oy);

            Console.WriteLine();
            ObjectRefIsEqual(ref ox, ref oy);
        }

My point is, when you box a variable you have to pay attention to how you work with it while it is boxed.  I have seen code where it was assumed that x==y is true when x and y both equal 1 and they are boxed as an object.