【问题标题】:How can I check whether a struct has been instantiated? [duplicate]如何检查结构是否已实例化? [复制]
【发布时间】:2012-10-01 12:39:26
【问题描述】:

我有一个结构(就这个问题而言)几乎模仿了内置的 Point 类型。

我需要在使用它之前检查它是否已经实例化。当它是Point 时,我可以这样做:

if (this.p == null)

但现在会产生以下错误:

运算符“==”不能应用于“ProportionPoint”和“”类型的操作数

如何将我的结构与 null 进行比较?还有其他方法可以检查实例化吗?

【问题讨论】:

  • 为什么要对类使用结构体?

标签: c# struct null


【解决方案1】:

struct 是一个值类型 - 它永远不会为空。

您可以检查default(ProportionPoint),这是结构的默认值(例如零)。但是,对于某个点,默认值(原点)可能也是“有效”值。

您可以改为使用Nullable<ProportionPoint>

【讨论】:

  • 谢谢。您对 origin = 默认值很了解。本来可以使用 nullable,但意识到我想要的行为比结构更好地匹配一个类。
【解决方案2】:

结构是值类型,与引用类型相反,它们永远不能为空。您可以检查默认值:

if (this.p.Equals(default(ProportionPoint)))

【讨论】:

  • 请注意,检查默认值不会让您区分“未初始化”值和“使用默认值正确初始化”值(例如 (0, 0))
  • @DarinDimitrov 不适合我。运算符“==”不能应用于“Vhdx.RegionTableEntry”和“Vhdx.RegionTableEntry”类型的操作数。
【解决方案3】:

结构不能为空。它是一个值类型,而不是引用类型。您需要检查具有默认值的属性。比如:

if(p.X == 0 && p.Y == 0)

【讨论】:

    【解决方案4】:

    因为 p 是 struct 它永远不会为空,所以你应该将它与它的默认值进行比较。为了检查您的值和默认值之间的等价性。 如果你使用 == 你会得到 ​​p>

    cannot be applied to operands of type 'ProportionPoint' and 'ProportionPoint' error
    

    因为默认情况下结构没有实现 ==。所以你需要像这样重载结构体中的 == 和 != 运算符:

    public static bool operator ==(firstOperand op1,  secondOperand2 op2) 
    {
        return op1.Equals(op2);
    }
    
    public static bool operator !=(firstOperand op1,  secondOperand2 op2) 
    {
       return !op1.Equals(op2);
    }
    

    然后:

    if (this.p == default(ProportionPoint))
    

    另一种选择是直接使用 Equals:

    f (this.p.Equals.default(ProportionPoint))
    

    【讨论】:

      【解决方案5】:

      一个结构永远不能为空,所以你不能将它与空进行比较。并且结构总是被初始化 - 如果不是由你初始化,那么由编译器使用默认值。

      【讨论】:

        【解决方案6】:

        使用可为空的:

        ProportionPoint? p1 = null;
        if (p1 == null) ...
        

        if (!p1.HasValue) ...
        

        【讨论】:

          【解决方案7】:

          我做了一个只适用于结构的扩展方法:

          public static bool IsNull<T>(this T source) where T:struct
          {
            return source.Equals(default(T));
          }
          

          调用约定:

          if(myStruct.IsNull())
            DoSomething();
          

          我知道它并没有真正检查它是否是null。但是,如果我给它一个更精确的名称,例如 IsEmptyIsDefault,六个月后我会忘记它的存在,并且在看到可用方法列表时不会选择它。从技术上讲,这不是空检查;但在概念上确实如此。

          【讨论】:

            【解决方案8】:

            结构不能为空,但如果您确实想在任何时候将与默认值等效的值存储在结构中,则根据其默认值检查结构的解决方法可能会给出假阴性。

            (例如,一个值为(0,0,0) 的结构可能是未修改的默认值,或者它可能将原点存储在3D 空间中。)

            避免这种假阴性问题的另一种方法是向结构添加另一个属性 - 例如bool 或 int - 跟踪数据是否实际存储在其中。然后让任何使用实际数据初始化结构的构造函数将此值设置为 true/1。在默认结构中,此值仍为 false/0,因此检查 default(MyStruct) 绝不应该给您一个假阴性,即使其中存储的所有其他数据都与默认值匹配。

            public Struct MyStruct { 
                public float x { get; private set; }
                public bool initialized { get; private set; }
            
                public MyStruct(float _x){
                    x=_x;
                    initialized = true;
                }
            }
            

            【讨论】:

              【解决方案9】:

              与引用类型的变量或值不同,它是对该类型的零个或一个实例的引用,结构变量或值结构实例.如果有一个以{Point myPoint; ...} 开头的代码块,并且该块中没有任何东西在MyPoint 上关闭(当块中有yield return 时,或者当 lambda 或匿名方法使用来自封闭块),则Point 的实例将在执行进入块之前的某个时间存在,并且可能在执行离开块后的任何时间停止存在。在任何可以使用结构类型变量的上下文中,结构都存在。

              所有结构类型都被认为具有无操作默认构造函数的原因之一是结构类型隐含地存在。当执行类似Point[] myPoints = new Point[100]; 的语句时,它会创建一个由100 个Point 结构组成的零填充数组;在此过程中,100 零填充的 Point 实例立即出现。在 C++ 中,如果一个类型具有构造函数,则创建该类型的数组将按顺序在数组的每个元素上调用构造函数,然后任何代码都可以访问该数组。如果在构造任何元素时抛出异常,编译器生成的代码将对在数组本身消失之前成功创建的每个元素运行确定性析构函数。虽然这是一个非常强大的功能,但将其包含在 .net 中会使框架大大复杂化。

              【讨论】:

                【解决方案10】:

                您不能检查结构是否为 null,但您可以检查默认的未初始化值,如下所示:

                if (instanceOfYourStruct == default)
                

                【讨论】:

                • 这应该是 C# 自 7.1(2019 年?)起新接受的答案
                猜你喜欢
                • 1970-01-01
                • 2020-08-04
                • 2019-12-27
                • 1970-01-01
                • 1970-01-01
                • 2014-03-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多