【问题标题】:when C# compare Nullable<T> == null, what happens?当 C# 比较 Nullable<T> == null 时,会发生什么?
【发布时间】:2022-02-10 21:23:38
【问题描述】:

当 C# 将一个可为空的类型与“null”进行比较时,C# 编译器是否会先插入一些代码来检查变量是否有值?

int? fk2=null;
OtherNullable<int> fk3=null;

Console.WriteLine(fk2 == null);

Console.WriteLine(fk3 == null);

上下文,我正在尝试计算等式 + 隐式和显式转换应该是什么样的,以启用 fk3 和 null 的比较。

假设您按照此处发布的代码实现了 Nullable:How does a Nullable<T> type work behind the scenes? 并将其命名为 OtherNullable&lt;T&gt;

只需稍加修改即可正常工作,只是 val == null 在运行时不起作用。

实施:

[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);
        }
    }

}

测试代码(不会编译——以前是这样):

[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);
    }
}

【问题讨论】:

    标签: c#


    【解决方案1】:

    任何Nullable&lt;T&gt;null 的相等性检查等效!nullable.HasValue。没有其他有意义的语义。我不确定OtherNullable&lt;T&gt; 的处理方式是什么,因为这不是标准类型。

    【讨论】:

    • 我添加了一个指向发布到 SO 的一些代码的链接。它应该是反射器将 Nullable 结构反编译成的。查看问题正文中的新信息。
    • @sgtz:如果问题是为什么fk3 == null 不起作用,答案是因为您没有overridden the equality operator。我还是不明白你为什么要自己实现OtherNullable
    • 查看 Bob2Civ 的回复。编译器确实插入代码。我确实覆盖了相等运算符。
    • 我的立场是正确的。又一次实施平等运算符......并且......它起作用了(请参阅更新的问题代码)。如果 C# 确实实现了上面列出的 if 测试,我想知道它是否为了速度而这样做?有趣的。感谢所有做出贡献的人。
    【解决方案2】:

    问:“当 C# 将可空类型与“空”进行比较时,C# 编译器会 先插入一些代码来检查变量是否有值?”

    答:编译器不会在这种情况下插入代码。在这种情况下,Equals 运算符被重写如下:

    public override bool Equals(object other)
    {
        if (!this.HasValue)
        {
            return (other == null);
        }
        if (other == null)
        {
            return false;
        }
        return this.value.Equals(other);
    }
    

    它负责将它与 null 进行比较。

    编译器确实通过以下方式帮助您:

    // this
    int? x = null;
    // Transformed to this
    int? x = new Nullable<int>()
    
    // this
    if (x == null) return;
    // Transformed to this
    if (!x.HasValue) return;
    
    // this
    if (x == 2) return;
    // Transformed to this
    if (x.GetValueOrDefault() == 2 && x.HasValue) return;
    

    所有这些信息都在你linked的问题中。

    感谢@barrylloyd 和@ChaosPandion

    【讨论】:

    • +1:我一定错过了 if (!x.HasValue) return;if (x.GetValueOrDefault() == 2 && x.HasValue)返回;。我认为您可能已经能够聪明地使用强制转换和相等重载。我会把这个问题留得更久一点,以防万一有人知道方法。 ty
    猜你喜欢
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 2016-09-05
    • 1970-01-01
    • 2019-05-27
    • 1970-01-01
    相关资源
    最近更新 更多