代码之家  ›  专栏  ›  技术社区  ›  Sekhat

结构、接口和装箱

  •  38
  • Sekhat  · 技术社区  · 14 年前


    Is it safe for structs to implement interfaces?

    使用以下代码:

    interface ISomeInterface
    {
        public int SomeProperty { get; }
    }
    
    struct SomeStruct : ISomeInterface
    {
        int someValue;
    
        public int SomeProperty { get { return someValue; } }
    
        public SomeStruct(int value)
        {
            someValue = value;
        }
    }
    

    然后我在某个地方这样做:

    ISomeInterface someVariable = new SomeStruct(2);
    

    SomeStruct

    4 回复  |  直到 8 年前
        1
  •  66
  •   Jon Skeet    14 年前

    是的,是的。基本上只要你需要 参考

    在这里, ISomeInterface 是一个接口,它是一个引用类型。因此 someVariable 始终是引用,因此必须将新创建的struct值装箱。

        2
  •  86
  •   Marc Gravell    14 年前

    乔恩的观点是正确的,但作为旁注,这条规则有一个小小的例外;仿制药。如果你有 where T : ISomeInterface 约束 special opcode . 这意味着可以使用该接口 没有

    public static void Foo<T>(T obj) where T : ISomeInterface {
        obj.Bar(); // Bar defined on ISomeInterface
    }
    

    确实如此 包括拳击,即使是价值类型 T . 但是,如果 Foo )您需要:

    ISomeInterface asInterface = obj;
    asInterface.Bar();
    

    约束 T .

        3
  •  10
  •   Dan Tao    14 年前

    我要把这个加到我的房间里 看看乔恩和马克的答案。

    考虑这种非泛型方法:

    public static void SetToNull(ref ISomeInterface obj) {
        obj = null;
    }
    

    ref 参数为null。那只可能是引用类型,对吗(好吧,还是暂时的 Nullable<T> ; 但是让我们忽略这种情况以保持简单。)因此,这个方法编译的事实告诉我们,声明为某个接口类型的变量必须被视为引用类型。

    这里的关键短语是“声明为”:考虑调用上述方法的尝试:

    var x = new SomeStruct();
    
    // This line does not compile:
    // "Cannot convert from ref SomeStruct to ref ISomeInterface" --
    // since x is declared to be of type SomeStruct, it cannot be passed
    // to a method that wants a parameter of type ref ISomeInterface.
    SetToNull(ref x);
    

    当然,你不能通过的原因 x SetToNull 是吗 ISomeInterface 为了你能通过 ref x --以及 因为编译器神奇地知道 塞托努尔 obj = null . 但在某种程度上,这正好强化了我的观点: 对象=空 正是因为 会的 宣布为 等轴测接口 方法。

    换句话说,如果变量被声明为 ,可以设置为null、pure和simple。这是因为接口是引用类型——因此,将一个对象声明为接口并将其赋给值类型object会框起该值。

    另一方面,考虑一下这个假设的通用方法:

    // This method does not compile:
    // "Cannot convert null to type parameter 'T' because it could be 
    // a non-nullable value type. Consider using 'default(T)' instead." --
    // since this method could take a variable declared as, e.g., a SomeStruct,
    // the compiler cannot assume a null assignment is legal.
    public static void SetToNull<T>(ref T obj) where T : ISomeInterface {
        obj = null;
    }
    
        4
  •  0
  •   sfuqua    14 年前

    MSDN documentation 告诉我们结构是值,而不是引用类型。当转换为类型的变量或从类型的变量转换时,它们被装箱 object . 但这里的中心问题是:一个接口类型的变量怎么办?既然接口也可以由类实现,那么这就等同于从一个值转换为一个引用类型,正如Jon Skeet已经说过的,因此肯定会发生装箱。 More discussion on an msdn blog .