C#
VB.NET
object comparison
programming languages
.NET framework

Why C fails to compare two object types with each other but VB doesn't?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

C# uses strict static type checking for the == operator — if two types have no defined equality operator between them, the code will not compile. VB.NET uses late-bound comparison via Option Strict Off (the default), where the = operator resolves at runtime using the VB runtime's comparison semantics. This means VB.NET allows comparisons between seemingly incompatible types that C# rejects at compile time. The difference reflects a fundamental design philosophy: C# favors compile-time safety while VB.NET favors developer convenience.

The Problem in C#

csharp
1class Foo { public int Value { get; set; } }
2class Bar { public int Value { get; set; } }
3
4var foo = new Foo { Value = 1 };
5var bar = new Bar { Value = 1 };
6
7// Compile error CS0019: Operator '==' cannot be applied to operands of type 'Foo' and 'Bar'
8bool result = foo == bar;

C# requires that the == operator is defined for the combination of types being compared. Since neither Foo nor Bar defines an operator == that accepts the other type, the compiler rejects the comparison.

The Same Code in VB.NET

vb
1' VB.NET with Option Strict Off (default)
2Dim foo As New Foo With {.Value = 1}
3Dim bar As New Bar With {.Value = 1}
4
5' This compiles and runs — uses late-bound comparison
6Dim result As Boolean = (foo = bar)
7' Result: False (reference comparison at runtime)

With Option Strict Off, VB.NET defers the comparison to the runtime, which performs a reference equality check. No compile error occurs.

Enabling Strict Mode in VB.NET

vb
1Option Strict On
2
3Dim foo As New Foo With {.Value = 1}
4Dim bar As New Bar With {.Value = 1}
5
6' NOW this fails: Option Strict On disallows late binding
7Dim result As Boolean = (foo = bar)  ' Compile error

Option Strict On makes VB.NET behave like C# — the comparison is rejected at compile time.

How C# == Resolution Works

csharp
1// For reference types without operator ==:
2// C# checks for a defined operator == between the two types
3// If none exists, and neither type is 'object', compilation fails
4
5object objFoo = new Foo();
6object objBar = new Bar();
7
8// This WORKS because both are typed as 'object'
9// Uses Object.ReferenceEquals semantics
10bool result = objFoo == objBar;  // false — different references
11
12// For value types:
13int a = 1;
14double b = 1.0;
15bool result2 = a == b;  // true — implicit conversion int → double, then ==

C# resolves == at compile time using the static types of the operands. If you cast to a common base type (object), the comparison compiles because object has a built-in == (reference equality).

Defining Custom == in C#

csharp
1class Foo
2{
3    public int Value { get; set; }
4
5    public static bool operator ==(Foo left, Bar right)
6    {
7        if (left is null || right is null) return ReferenceEquals(left, right);
8        return left.Value == right.Value;
9    }
10
11    public static bool operator !=(Foo left, Bar right)
12    {
13        return !(left == right);
14    }
15
16    public override bool Equals(object obj)
17    {
18        if (obj is Bar bar) return Value == bar.Value;
19        if (obj is Foo foo) return Value == foo.Value;
20        return false;
21    }
22
23    public override int GetHashCode() => Value.GetHashCode();
24}
25
26// Now this compiles:
27var foo = new Foo { Value = 1 };
28var bar = new Bar { Value = 1 };
29bool result = foo == bar;  // true

Using Equals Instead of ==

csharp
1var foo = new Foo { Value = 1 };
2var bar = new Bar { Value = 1 };
3
4// Equals is a virtual method on object — always callable
5bool result = foo.Equals(bar);  // false (default Object.Equals is reference equality)
6
7// Override Equals in Foo:
8// public override bool Equals(object obj) => obj is Bar b && Value == b.Value;
9// Then: foo.Equals(bar) returns true

Equals() always compiles because it is defined on object. The == operator requires explicit type compatibility.

Comparison Summary

ScenarioC#VB.NET (Strict Off)VB.NET (Strict On)
foo == bar (unrelated types)Compile errorCompiles (late bound)Compile error
objFoo == objBar (typed as object)Compiles (ref equality)Compiles (ref equality)Compiles
1 == 1.0 (numeric conversion)Compiles (true)Compiles (true)Compiles (true)
"abc" == "abc" (string)Compiles (true, value)Compiles (true, value)Compiles

Is Operator in VB.NET vs == in C#

vb
1' VB.NET: "Is" always does reference comparison
2Dim result As Boolean = (foo Is bar)  ' Compile error if unrelated types with Option Strict On
3
4' "=" can do value comparison (late-bound with Option Strict Off)
5Dim result2 As Boolean = (foo = bar)  ' Late-bound comparison
csharp
// C# equivalent of VB's "Is":
bool result = ReferenceEquals(foo, bar);
// Or: object.ReferenceEquals(foo, bar)

Common Pitfalls

  • Assuming VB.NET = is the same as C# ==: VB.NET's = operator with Option Strict Off performs late-bound comparison that can succeed at runtime for types that C# would reject at compile time. This can mask bugs that C# would catch during compilation.
  • Forgetting to override Equals when defining ==: C# requires that if you define operator ==, you should also override Equals() and GetHashCode(). Not doing so produces compiler warning CS0660/CS0661 and can cause inconsistent behavior between == and .Equals().
  • Using == on two object-typed variables: object a = "hello"; object b = "hello"; a == b may return true or false depending on string interning. This uses reference equality, not value equality. Use Equals() for value comparison when types are unknown.
  • Mixing value types and reference types: 1 == (object)1 in C# compiles but returns false because the boxed integer is a different reference. Use .Equals() or unbox before comparing.
  • Not enabling Option Strict On in VB.NET: Option Strict Off (the default) allows late-bound operations that hide type errors until runtime. For large projects, always enable Option Strict On to get compile-time type safety comparable to C#.

Summary

  • C# requires a defined == operator between two types — compile error if missing
  • VB.NET with Option Strict Off (default) allows late-bound comparison using the = operator
  • VB.NET with Option Strict On behaves like C# and rejects incompatible type comparisons
  • Cast both operands to object in C# to force reference equality comparison
  • Define custom operator == in C# when cross-type comparison is needed
  • Always override Equals and GetHashCode alongside operator ==

Course illustration
Course illustration

All Rights Reserved.