when C# compare Nullable<T> == null, what happens?
<p>When C# compares a nullable type to a "null", does the C# compiler insert some code to check if the variable has a value first?</p>

<pre><code>int? fk2=null;
OtherNullable&lt;int&gt; fk3=null;

Console.WriteLine(fk2 == null);

Console.WriteLine(fk3 == null);
</code></pre>

<p>Context, I'm trying to work out what the equality + implicit, and explicit cast should look like to enable the comparison of fk3 and null.</p>

<p>Say that you implemented Nullable as per the code posted here: <a href="http://stackoverflow.com/questions/5602773/how-does-a-nullablet-type-work-behind-the-scenes">How does a Nullable&lt;T&gt; type work behind the scenes?</a> and called it <code>OtherNullable&lt;T&gt;</code></p>

<p>This works fine with little modification, except that val == null will not work at runtime.</p>

<p>Implementation:</p>

<pre><code>[Serializable, StructLayout(LayoutKind.Sequential)]
public struct OtherNullable&lt;T&gt; : IEquatable&lt;OtherNullable&lt;T&gt;&gt; where T : struct {

    private bool hasValue;
    internal T value;

    public OtherNullable(T value)
        : this() {
        this.value = value;
        this.hasValue = true;
    }

    public OtherNullable(T? value) {
        this.value = default(T);
        this.hasValue = false;
    }

    public bool HasValue {
        get { return this.hasValue; }
    }

    public T Value {
        get {
            if (!this.HasValue) {
                throw new InvalidOperationException("No Value");
            }
            return this.value;
        }
    }

    public OtherNullable(bool b) {
        this.value = default(T);
        this.hasValue = false;
    }

    public T GetValueOrDefault() {
        return this.value;
    }

    public T GetValueOrDefault(T defaultValue) {
        if (!this.HasValue) {
            return defaultValue;
        }
        return this.value;
    }

    public bool Equals(OtherNullable&lt;T&gt; other)
    {
        if (!other.HasValue &amp; !this.HasValue)
            return true;
        else
            return other.hasValue.Equals(hasValue) &amp;&amp; other.value.Equals(value);
    }

    public static bool operator ==(OtherNullable&lt;T&gt; left, OtherNullable&lt;T&gt; right) {
        return left.Equals(right);
    }

    public static bool operator !=(OtherNullable&lt;T&gt; left, OtherNullable&lt;T&gt; right) {
        return !left.Equals(right);
    }

    public override bool Equals(object other) {
        if (ReferenceEquals(null, other)) return false;
        if (other.GetType() != typeof(OtherNullable&lt;T&gt;)) return false;
        return Equals((OtherNullable&lt;T&gt;)other);
    }

    public override int GetHashCode() {
        unchecked {
            return (hasValue.GetHashCode() * 397) ^ value.GetHashCode();
        }
    }

    public override string ToString() {
        if (!this.HasValue) {
            return "";
        }
        return this.value.ToString();
    }

    public static implicit operator OtherNullable&lt;T&gt;(T value) {
        return new OtherNullable&lt;T&gt;(value);
    }

    public static explicit operator T(OtherNullable&lt;T&gt; value) {
        return value.Value;
    }

    public static implicit operator OtherNullable&lt;T&gt;(Nullable&lt;T&gt; value) {
        if (value.HasValue) {
            return new OtherNullable&lt;T&gt;(value.Value);
        } else {
            return new OtherNullable&lt;T&gt;(null);
        }
    }

}
</code></pre>

<p>Test Code (will not compile -- it was previously):</p>

<pre><code>[TestFixture]
public class TestOtherNullable {
    [Test]
    public void Test()
    {
        var a = new OtherNullable&lt;int&gt;();

        a = 1;

        Assert.IsTrue(a.HasValue);
        Assert.IsFalse(a == null);

        var b = new OtherNullable&lt;int&gt;();
        b = null;
        Assert.IsTrue(b == null);
    }
}
</code></pre>
