56

可能重复:
结构实现接口是否安全?

拿这个代码:

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

4 回答 4

94

乔恩的观点是正确的,但作为旁注,该规则有一个轻微的例外;仿制药。如果有where T : ISomeInterface,那么这是受约束的,并且使用特殊的操作码。这意味着该界面可以在没有装箱的情况下使用。例如:

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

这不涉及装箱,即使对于 value-type 也是如此T。但是,如果(在同一个Foo)你这样做:

ISomeInterface asInterface = obj;
asInterface.Bar();

然后那个盒子像以前一样。约束 直接适用于T

于 2010-06-13T18:13:26.353 回答
71

是的。基本上,每当您需要参考并且您只有一个值类型值时,该值就会被装箱。

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

于 2010-06-13T15:29:02.360 回答
12

我添加这个是为了希望对 Jon 和 Marc 提供的答案有更多的了解。

考虑这种非泛型方法:

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

嗯...将ref参数设置为空。那可能只是参考类型,对吗?(好吧,或者对于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上述代码传递给的原因SetToNullx需要将其声明ISomeInterface为您才能通过ref x- 而不是因为编译器神奇地知道SetToNull包含行obj = null. 但是以某种方式强化了我的观点:该obj = null行是合法的,正是因为声明为 an的变量传递给方法是非法的。ISomeInterface

换句话说,如果一个变量被声明为一个ISomeInterface,它可以被设置为空,纯粹和简单。那是因为接口是引用类型——因此,将对象声明为接口并将其分配给值类型对象框该值。

现在,另一方面,考虑这个假设的泛型方法:

// 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;
}
于 2010-06-13T18:48:57.670 回答
0

MSDN 文档告诉我们结构是值,而不是引用类型。当转换到/从类型的变量时,它们被装箱object。但这里的中心问题是:接口类型的变量呢?由于接口也可以由类实现,因此这必须等同于从值转换为引用类型,正如 Jon Skeet 已经说过的那样,因此会发生装箱。有关 msdn 博客的更多讨论

于 2010-06-13T16:56:18.513 回答