将结构与 null 进行比较 [英] Comparing structs to null

查看:19
本文介绍了将结构与 null 进行比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能的重复:
C# 可以将值类型与 null 进行比较

我正在多线程环境中开发 Windows 应用程序,有时会收到异常在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke."所以我想我只需要添加这行代码:

I was working on a windows app in a multithreaded environment and would sometimes get the exception "Invoke or BeginInvoke cannot be called on a control until the window handle has been created." So I figured that I'd just add this line of code:

if(this.Handle != null)
{
   //BeginInvokeCode
}

但这并没有解决问题.所以我进一步挖掘,并意识到 IntPtr(Form.Handle 的类型)是一个不能为空的结构.这是有效的修复:

But that didn't solve the problem. So I dug a little further, and realized that IntPtr (the type that Form.Handle is) is a struct which can't be nullable. This was the fix that worked:

if(this.Handle != IntPtr.Zero)
{
   //BeginInvokeCode
}

然后它击中了我,为什么在我检查它的 null 时它甚至编译?所以我决定自己尝试一下:

So then it hit me, why did it even compile when I was checking it for null? So I decided to try it myself:

    public struct Foo { }

然后:

    static void Main(string[] args)
    {
        Foo f = new Foo();
        if (f == null) { }
    }

果然它没有编译说错误1运算符'=='不能应用于'ConsoleApplication1.Foo'和''类型的操作数".好的,然后我开始查看 IntPtr 的元数据,并开始将所有内容添加到 IntPtr 结构(ISerializable、ComVisible)中的 Foo 结构中,但没有任何帮助.最后,当我添加 == 和 != 的运算符重载时,它起作用了:

and sure enough it didn't compile saying that "Error 1 Operator '==' cannot be applied to operands of type 'ConsoleApplication1.Foo' and ''". Ok, so then I started looking at the metadata for IntPtr and started adding everything to my Foo struct that was there in the IntPtr struct (ISerializable, ComVisible) but nothing helped. Finally, when I added the operator overloading of == and !=, it worked:

[Serializable]
[ComVisible(true)]
public struct Foo : ISerializable
{
    #region ISerializable Members

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        throw new NotImplementedException();
    }

    #endregion

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public static bool operator ==(Foo f1, Foo f2) { return false; }
    public static bool operator !=(Foo f1, Foo f2) { return false; }
}

这终于编译了:

    static void Main(string[] args)
    {
        Foo f = new Foo();
        if (f == null) { }
    }

我的问题是为什么?为什么如果覆盖 == 和 != 就可以与 null 进行比较?== 和 != 的参数仍然是不能为空的 Foo 类型,那么为什么突然允许呢?

My question is why? Why if you override == and != are you allowed to compare to null? The parameters to == and != are still of type Foo which aren't nullable, so why's this allowed all of a sudden?

推荐答案

看起来问题是当 MS 引入可为空类型时,他们使每个结构都可以隐式转换为其可为空类型(foo?),所以代码

It looks like the issue is that when MS introduced nullable types, they made it so that every struct is implicitly convertable to its nullable type (foo?), so the code

if( f == null)

相当于

if ( (Nullable<foo>)f == (Nullable<foo>)null) 

因为 MSDN 声明存在于值类型的任何用户定义的运算符也可以由可空类型使用",所以当您覆盖 operator== 时,您允许隐式转换编译,如您现在有一个用户定义的 == —— 免费为您提供可为空的重载.

Since MSDN states that "any user-defined operators that exist for value types may also be used by nullable types", when you override operator==, you allow that implicit cast to compile, as you now have a user-defined == -- giving you the nullable overload for free.

旁白:

好像在你的例子中,有一些编译器优化编译器发出的唯一一个甚至暗示有测试的东西就是这个 IL:

Seems like in your example, there is some compiler optimization The only thing that is emitted by the compiler that even hints there was a test is this IL:

ldc.i4.0
ldc.i4.0
ceq
stloc.1   //where there is an unused boolean local

注意如果你把main改成

Note that if you change main to

Foo f = new Foo();
object b = null;
if (f == b) { Console.WriteLine("?"); }

它不再编译.但是如果你把结构装箱:

It no longer compiles. But if you box the struct:

Foo f = new Foo();
object b = null;
if ((object)f == b) { Console.WriteLine("?"); }

如果编译,发出 IL,并按预期运行(结构永远不会为空);

if compiles, emits IL, and runs as expected (the struct is never null);

这篇关于将结构与 null 进行比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆