结构、接口和装箱
可能的重复:
结构实现接口安全吗?
获取此代码:
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
是否已装箱?
Possible Duplicate:
Is it safe for structs to implement interfaces?
Take this code:
interface ISomeInterface
{
public int SomeProperty { get; }
}
struct SomeStruct : ISomeInterface
{
int someValue;
public int SomeProperty { get { return someValue; } }
public SomeStruct(int value)
{
someValue = value;
}
}
and then I do this somewhere:
ISomeInterface someVariable = new SomeStruct(2);
is the SomeStruct
boxed in this case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
乔恩的观点是正确的,但作为旁注,该规则有一个轻微的例外:仿制药。如果您有
where T : ISomeInterface
,那么这是受约束的,并且使用 特殊操作码。这意味着该接口可以在没有装箱的情况下使用。例如:这不涉及装箱,即使对于值类型
T
也是如此。但是,如果(在同一个Foo
中)您这样做:那么该框将像以前一样。 受约束仅直接适用于
T
。Jon's point is true, but as a side note there is one slight exception to the rule; generics. If you have
where T : ISomeInterface
, then this is constrained, and uses a special opcode. This means the interface can be used without boxing. For example:This does not involve boxing, even for value-type
T
. However, if (in the sameFoo
) you do:then that boxes as before. The constrained only applies directly to
T
.是的。基本上,每当您需要引用并且您只有一个值类型值时,该值就会被装箱。
这里,
ISomeInterface
是一个接口,它是一个引用类型。因此,someVariable
的值始终是一个引用,因此必须对新创建的结构体值进行装箱。Yes, it is. Basically whenever you need a reference and you've only got a value type value, the value is boxed.
Here,
ISomeInterface
is an interface, which is a reference type. Therefore the value ofsomeVariable
is always a reference, so the newly created struct value has to be boxed.我添加此内容是为了希望对 Jon 和 Marc 提供的答案有更多的了解。
考虑这个非泛型方法:
嗯...将
ref
参数设置为 null。这可能仅适用于引用类型,对吗? (好吧,或者对于Nullable
;但是让我们忽略这种情况以保持简单。)因此,此方法编译的事实告诉我们,声明为某种接口类型的变量必须是被视为引用类型。这里的关键短语是“声明为”:考虑调用上述方法的尝试:
当然,您无法将上述代码中的
x
传递给SetToNull
的原因是x
需要声明为ISomeInterface
以便您能够传递ref x
——而不能 因为编译器神奇地知道SetToNull
包含行obj = null
。但在某种程度上,这只是强化了我的观点:obj = null
行是合法的,正是因为传递变量非法 >未声明为该方法的ISomeInterface
。换句话说,如果将变量声明为 ISomeInterface,则可以将其设置为 null,纯粹且简单。这是因为接口是引用类型——因此,将对象声明为接口并将其分配给值类型对象会将该值框起来。
现在,另一方面,考虑这个假设的通用方法:
I'm adding this to hopefully shed a little more light on the answers offered by Jon and Marc.
Consider this non-generic method:
Hmm... setting a
ref
parameter to null. That's only possibly for a reference type, correct? (Well, or for aNullable<T>
; but let's ignore that case to keep things simple.) So the fact that this method compiles tells us that a variable declared to be of some interface type must be treated as a reference type.The key phrase here is "declared as": consider this attempt to call the above method:
Granted, the reason you can't pass
x
in the above code toSetToNull
is thatx
would need to be declared as anISomeInterface
for you to be able to passref x
-- and not because the compiler magically knows thatSetToNull
includes the lineobj = null
. But in a way that just reinforces my point: theobj = null
line is legal precisely because it would be illegal to pass a variable not declared as anISomeInterface
to the method.In other words, if a variable is declared as an
ISomeInterface
, it can be set to null, pure and simple. And that's because interfaces are reference types -- hence, declaring an object as an interface and assigning it to a value type object boxes that value.Now, on the other hand, consider this hypothetical generic method:
MSDN 文档告诉我们结构体是有价值的,不是引用类型。当与
object
类型的变量进行转换时,它们会被装箱。但这里的核心问题是:接口类型的变量怎么样?由于接口也可以由类实现,那么这必定相当于从值转换为引用类型,正如 Jon Skeet 已经说过的那样,因此会发生装箱。 在 msdn 博客上进行更多讨论。The MSDN documentation tells us that structs are value, not reference types. They are boxed when converting to/from a variable of type
object
. But the central question here is: what about a variable of an interface type? Since the interface can also be implemented by a class, then this must be tantamount to converting from a value to a reference type, as Jon Skeet already said, therefore yes boxing would occur. More discussion on an msdn blog.