在 C# 中装箱值类型的用例?
在某些情况下,a 的实例 值类型需要被视为 引用类型的实例。 对于 像这样的情况,值类型 实例可以转换为 通过a引用类型实例 过程称为拳击。 当一个值 类型实例已装箱,存储为 分配在堆上和 实例的值被复制到其中 空间。 对此存储的引用是 放置在堆栈上。 盒装值 是一个对象,一个引用类型 包含值的内容 类型实例。
在 Wikipedia 有一个 Java 示例。 但在 C# 中,在哪些情况下必须对值类型进行装箱? 或者一个更好/类似的问题是,为什么要在堆(装箱)而不是堆栈上存储值类型?
There are cases when an instance of a
value type needs to be treated as an
instance of a reference type. For
situations like this, a value type
instance can be converted into a
reference type instance through a
process called boxing. When a value
type instance is boxed, storage is
allocated on the heap and the
instance's value is copied into that
space. A reference to this storage is
placed on the stack. The boxed value
is an object, a reference type that
contains the contents of the value
type instance.
In Wikipedia there is an example for Java. But in C#, what are some cases where one would have to box a value type? Or would a better/similar question be, why would one want to store a value type on the heap (boxed) rather than on the stack?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
一般来说,您通常希望避免对值类型进行装箱。
然而,在极少数情况下这是有用的。 例如,如果您需要以 1.1 框架为目标,您将无法访问通用集合。 在 .NET 1.1 中对集合的任何使用都需要将值类型视为 System.Object,这会导致装箱/拆箱。
在某些情况下,这在 .NET 2.0+ 中仍然有用。 任何时候您想要利用所有类型(包括值类型)都可以直接视为对象的事实,您可能需要使用装箱/拆箱。 这有时很方便,因为它允许您保存集合中的任何类型(通过在泛型集合中使用对象而不是 T),但一般来说,最好避免这种情况,因为您会失去类型安全性。 然而,频繁发生装箱的一种情况是当您使用反射时 - 在处理值类型时,反射中的许多调用将需要装箱/拆箱,因为事先不知道该类型。
In general, you typically will want to avoid boxing your value types.
However, there are rare occurances where this is useful. If you need to target the 1.1 framework, for example, you will not have access to the generic collections. Any use of the collections in .NET 1.1 would require treating your value type as a System.Object, which causes boxing/unboxing.
There are still cases for this to be useful in .NET 2.0+. Any time you want to take advantage of the fact that all types, including value types, can be treated as an object directly, you may need to use boxing/unboxing. This can be handy at times, since it allows you to save any type in a collection (by using object instead of T in a generic collection), but in general, it is better to avoid this, as you're losing type safety. The one case where boxing frequently occurs, though, is when you're using Reflection - many of the calls in reflection will require boxing/unboxing when working with value types, since the type is not known in advance.
几乎没有充分的理由故意对值类型进行装箱。 几乎总是,对值类型进行装箱的原因是将其存储在某个不支持类型识别的集合中。 例如,旧的 ArrayList 是一个集合对象,它们是引用类型。 收集整数的唯一方法是将它们装箱为对象并将它们传递给 ArrayList。
如今,我们有了通用集合,所以这不再是一个问题。
There is almost never a good reason to deliberately box a value type. Almost always, the reason to box a value type is to store it in some collection that is not type aware. The old ArrayList, for example, is a collection of objects, which are reference types. The only way to collect, say, integers, is to box them as objects and pass them to ArrayList.
Nowadays, we have generic collections, so this is less of an issue.
在 .NET 中,装箱通常会在必要时自动发生; 通常当您将值类型传递给需要引用类型的对象时。 一个常见的例子是 string.Format()。 当您将原始值类型传递给此方法时,它们将作为调用的一部分进行装箱。 所以:
这说明了一个简单的场景,其中值类型 (x) 被自动装箱以传递给需要对象的方法。 一般来说,您希望尽可能避免对值类型进行装箱……但在某些情况下它非常有用。
有趣的是,当您在 .NET 中使用泛型时,值类型在用作类型的参数或成员时不会被装箱。 这使得泛型比旧的 C# 代码(例如 ArrayList)更高效,旧的 C# 代码将所有内容都视为与类型无关的 {object}。 这又增加了使用泛型集合的理由,例如使用
List
或Dictionary
而不是ArrayList
或Hashtable
。Boxing generally happens automatically in .NET when they have to; often when you pass a value type to something that expects a reference type. A common example is string.Format(). When you pass primitive value types to this method, they are boxed as part of the call. So:
This illustrates a simple scenario where a value type (x) is automatically boxed to be passed to a method that expects an object. Generally, you want to avoid boxing value types when possible ... but in some cases it's very useful.
On an interesting aside, when you use generics in .NET, value types are not boxed when used as parameters or members of the type. Which makes generics more efficient than older C# code (such as ArrayList) that treat everything as {object} to be type agnostic. This adds one more reason to use generic collections, like
List<T>
orDictionary<T,K>
overArrayList
orHashtable
.我会向您推荐 Eric Lippert 的 2 篇精彩文章
http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx
http://blogs.msdn .com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx
这是我百分百同意的引用
在 99% 的应用程序中,开发人员不应该关心为什么值类型在堆栈中而不是在堆中,以及我们在这里可以获得什么性能提升。 Juts 牢记非常简单的规则:
必要时,使用泛型集合。
大多数问题并非发生在您
定义你自己的类型,但是当你
不正确地使用现有类型
(由 Microsoft 或您的定义
同事)
简单的。 如果你需要一个结构
有 10-20 个字段,我想你会
更好地创建一个类。 想象一下,所有
每次都会复制该字段
当你偶尔通过它时
按值函数...
值类型与引用类型
里面的字段。 就像结构一样
字符串和对象字段。
所需的功能,而不是在哪里
它应该被存储。 结构体有
与相比功能有限
类,所以如果结构不能提供
所需的功能,例如
默认构造函数,定义类。
使用其他人的数据进行的操作
类型,它通常被定义为
班级。 对于结构操作
应该定义不同的类型
仅当您可以将一种类型转换为
其他。 假设你可以添加 int 到
double 因为你可以将 int 转换为
双倍的。
任何规则都允许在特殊情况下排除,但不要尝试过度优化。
附注
我遇到了一些具有 2-3 年经验的 ASP.NET 开发人员,他们不知道堆栈和堆之间的区别。 :-( 如果我是面试官,我不会雇用这样的人,但这并不是因为装箱/拆箱可能成为我见过的任何 ASP.NET 网站的瓶颈。
I would recommend you 2 nice articles of Eric Lippert
http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx
http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx
Here is the quote that I would 100% agree with
In 99% applications developers should not care about why Value types are in stack and not in the heap and what performance gain could we have here. Juts have in mind very simple rules:
necessary, use generics collections.
Most problems occurs not when you
define your own types, but when you
use existing types inproperly
(defined by Microsoft or your
collegues)
simple. If you need to have a struct
with 10-20 fields, I suppose you'ld
better create a class. Imagine, all
that fields will be copied each time
when you occasionally pass it a
function by value...
value types with reference type
fields inside. Like struct with
String and object fields.
required functionality, not on where
it should be stored. Structs have
limited functionality comparing to
classes, so if struct cannot provide
the required functionality, like
default constructor, define class.
actions with the data of other
types, it is usually defined as a
class. For structs operations with
different types should be defined
only if you can cast one type to
another. Say you can add int to
double because you can cast int to
double.
Any rules allows exclusions in special cases, but do not try to over-optimize.
p.s.
I met some ASP.NET developers with 2-3 years experience who doesn't know the difference between stack and heap. :-( I would not hire such a person if I'm an interviewer, but not because boxing/unboxing could be a bottleneck in any of ASP.NET sites I've ever seen.
我认为 C# 中装箱的一个很好的例子出现在非通用集合中,例如 ArrayList。
I think a good example of boxing in c# occurs in the non-generic collections like ArrayList.
一个例子是当方法采用对象参数并且必须传入值类型时。
One example would when a method takes an object parameter and a value type must be passed in.
下面是一些装箱/拆箱的示例
Below is some examples of boxing/unboxing
发生这种情况的情况之一是,例如,如果您有需要类型对象参数的方法,并且您正在传入一种基本类型(例如 int)。 或者,如果您将参数定义为 int 类型的“ref”。
One of the situations when this happens is for example if you have method that expect parameter of type object and you are passing in one of the primitive types, int for example. Or if you define parameter as 'ref' of type int.
该代码
实际上是装箱和拆箱的,因为
Writeline
在内部进行了int
转换。 为了避免这种情况,您可以注意微妙的错误!
您可以通过将您自己的类型声明为
struct
来声明您自己的值类型。 想象一下,您声明一个具有大量属性的struct
,然后将一些实例放入ArrayList
中。 这当然会限制他们。 现在通过[]
运算符引用一个,将其转换为类型并设置一个属性。 您只需在副本上设置属性。ArrayList
中的那个仍然没有修改。因此,值类型必须始终是不可变的,即使所有成员变量只读,以便它们只能在构造函数中设置,并且没有任何可变类型作为成员。
The code
actually boxes and unboxes because
Writeline
does anint
cast inside. To avoid this you could doBeware of subtle bugs!
You can declare your own value types by declaring your own type as
struct
. Imagine you declare astruct
with lots of properties and then put some instances inside anArrayList
. This boxes them of course. Now reference one through the[]
operator, casting it to the type and set a property. You just set a property on a copy. The one in theArrayList
is still unmodified.For this reason, value types must always be immutable, i.e. make all member variables
readonly
so that they can only be set in the constructor and do not have any mutable types as members.