结构、接口和装箱

发布于 2024-09-05 02:49:27 字数 622 浏览 15 评论 0原文

可能的重复:
结构实现接口安全吗?

获取此代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽梦忆笙歌 2024-09-12 02:49:27

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

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

涉及装箱,即使对于值类型T也是如此。但是,如果(在同一个 Foo 中)您这样做:

ISomeInterface asInterface = obj;
asInterface.Bar();

那么该框将像以前一样。 受约束直接适用于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:

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

This does not involve boxing, even for value-type T. However, if (in the same Foo) you do:

ISomeInterface asInterface = obj;
asInterface.Bar();

then that boxes as before. The constrained only applies directly to T.

浅沫记忆 2024-09-12 02:49:27

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

这里,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 of someVariable is always a reference, so the newly created struct value has to be boxed.

命硬 2024-09-12 02:49:27

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

考虑这个非泛型方法:

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

嗯...将 ref 参数设置为 null。这可能仅适用于引用类型,对吗? (好吧,或者对于 Nullable;但是让我们忽略这种情况以保持简单。)因此,此方法编译的事实告诉我们,声明为某种接口类型的变量必须是被视为引用类型。

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

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,则可以将其设置为 null,纯粹且简单。这是因为接口是引用类型——因此,将对象声明为接口并将其分配给值类型对象会将该值框起来。

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

// 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;
}

I'm adding this to hopefully shed a little more light on the answers offered by Jon and Marc.

Consider this non-generic method:

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

Hmm... setting a ref parameter to null. That's only possibly for a reference type, correct? (Well, or for a Nullable<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:

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);

Granted, the reason you can't pass x in the above code to SetToNull is that x would need to be declared as an ISomeInterface for you to be able to pass ref x -- and not because the compiler magically knows that SetToNull includes the line obj = null. But in a way that just reinforces my point: the obj = null line is legal precisely because it would be illegal to pass a variable not declared as an ISomeInterface 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:

// 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;
}
人间不值得 2024-09-12 02:49:27

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文