Probably reference equality - checking for value equality is unintuitive and inconsistent for objects. By default == is a reference equality check.

object a = 1;
object b = 1;
Assert.IsFalse (a == b);

a doesn’t equal b because boxing creates one object instance for a, and another instance is created for b (two different locations in memory containing the same data). The double equals, ==, is a “reference type equality operator” and will only compare the object references.

Using any of these methods work as expected:

Assert.IsTrue (a.Equals (b));
Assert.IsTrue (((int)a).Equals (b));
Assert.IsTrue (Object.Equals (a, b));
Assert.IsTrue ((int)a == (int)b);

When passing objects around, the simple solution is to use the Equals() method as it may perform value equality if the object overrides Equals(). So, value equality can be accomplished for individual objects, but you hit this problem again with collections:

Assert.IsFalse (
    new string[] { "abc", "def" }.Equals (
    new string[] { "abc", "def" }));
Assert.IsFalse (
	new int[] { 1, 2, 3 }.Equals (
	new int[] { 1, 2, 3 }));
Assert.IsFalse (
    new object[] { 4, "stuff", DateTime.Parse ("1/1/2004 1:00 AM") }.Equals (
    new object[] { 4, "stuff", DateTime.Parse ("January 1, 2004 01:00") }));

There is only reference equality with ArrayList:

Assert.IsFalse (
    new System.Collections.ArrayList (new int[] { 1, 2, 3 }) ==
    new System.Collections.ArrayList (new int[] { 1, 2, 3 }));
Assert.IsFalse (
    new System.Collections.ArrayList (new int[] { 1, 2, 3 }).Equals (
    new System.Collections.ArrayList (new int[] { 1, 2, 3 })));
Info
In .NET Framework 3.5 (released 2007), SequenceEqual was introduced.

And now:

Assert.IsTrue(new int[] { 1, 2, 3 }.SequenceEqual(
    new int[] { 1, 2, 3 }));
Assert.IsTrue(new int[] { 1, 2, 3 }.SequenceEqual(
    new int[] { 1, 2, 3 }));
Assert.IsTrue(new object[] { 1, 2, 3 }.SequenceEqual(
    new object[] { 1, 2, 3 }));
Assert.IsTrue(new object[] { 4, "stuff", DateTime.Parse("1/1/2004 1:00 AM") }.SequenceEqual(
    new object[] { 4, "stuff", DateTime.Parse("January 1, 2004 01:00") }));

Here’s a real world example:

/// <summary>Always accepts the public key hardcoded in the byte array as a valid certificate.</summary>
public sealed class AcceptTrustedCertificate : ICertificatePolicy {
    public bool CheckValidationResult (
        ServicePoint srvPoint,
        X509Certificate certificate,
        WebRequest request,
        int certificateProblem) {
        // return true if certificate returned is equal to the certificate's public key
        return certificate.GetPublicKey().SequenceEqual(
            new byte[] { 48, 130, 1, 10, 2, 130, 1, 1, 0, 206, 214, 212 });
    }
}

ServicePointManager.CertificatePolicy = new AcceptTrustedCertificate();

Note

2002: The ICertificatePolicy interface was used to provide custom security certificate validation for the .NET Framework.

This has been replaced by the ServerCertificateValidationCallback property on the ServicePointManager or, for HTTP specifically, the ServerCertificateCustomValidationCallback property on the HttpClientHandler, who can be specified as a parameter to HttpClient.