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?
int? fk2=null;
OtherNullable<int> fk3=null;
Console.WriteLine(fk2 == null);
Console.WriteLine(fk3 == null);
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.
Say that you implemented Nullable as per the code posted here: How does a Nullable<T> type work behind the scenes? and called it OtherNullable<T>
This works fine with little modification, except that val == null will not work at runtime.
Implementation:
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct OtherNullable<T> : IEquatable<OtherNullable<T>> 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<T> other)
{
if (!other.HasValue & !this.HasValue)
return true;
else
return other.hasValue.Equals(hasValue) && other.value.Equals(value);
}
public static bool operator ==(OtherNullable<T> left, OtherNullable<T> right) {
return left.Equals(right);
}
public static bool operator !=(OtherNullable<T> left, OtherNullable<T> right) {
return !left.Equals(right);
}
public override bool Equals(object other) {
if (ReferenceEquals(null, other)) return false;
if (other.GetType() != typeof(OtherNullable<T>)) return false;
return Equals((OtherNullable<T>)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<T>(T value) {
return new OtherNullable<T>(value);
}
public static explicit operator T(OtherNullable<T> value) {
return value.Value;
}
public static implicit operator OtherNullable<T>(Nullable<T> value) {
if (value.HasValue) {
return new OtherNullable<T>(value.Value);
} else {
return new OtherNullable<T>(null);
}
}
}
Test Code (will not compile -- it was previously):
[TestFixture]
public class TestOtherNullable {
[Test]
public void Test()
{
var a = new OtherNullable<int>();
a = 1;
Assert.IsTrue(a.HasValue);
Assert.IsFalse(a == null);
var b = new OtherNullable<int>();
b = null;
Assert.IsTrue(b == null);
}
}