拿这段代码:
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
?
答案 0 :(得分:62)
乔恩的观点是正确的,但作为旁注,该规则有一个轻微的例外;仿制药。如果您有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
。
答案 1 :(得分:48)
是的,确实如此。基本上,只要您需要引用并且您只获得了值类型值,该值就会被加框。
这里,ISomeInterface
是一个接口,它是一个引用类型。因此someVariable
的值始终是引用,因此必须将新创建的struct值装箱。
答案 2 :(得分:8)
我正在添加这个,希望能够更多地了解Jon和Marc提供的答案
。考虑这种非通用方法:
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
的原因是x
需要声明为ISomeInterface
才能成为ref x
能够通过SetToNull
- 和而不是,因为编译器神奇地知道obj = null
包含行obj = null
。但是在某种程度上只是强调了我的观点: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;
}
,则可以将其设置为null,纯粹且简单。这是因为接口是引用类型 - 因此,将对象声明为接口并将其分配给值类型的值对象框。
另一方面,现在考虑这个假设的通用方法:
{{1}}
答案 3 :(得分:0)
MSDN documentation告诉我们结构是值,而不是引用类型。转换为/ object
类型的变量时,它们会被装箱。但这里的核心问题是:接口类型的变量怎么样?由于接口也可以由类实现,因此这必须等同于从值转换为引用类型,正如Jon Skeet已经说过的那样,因此会发生拳击。 More discussion on an msdn blog