在 C# 中装箱值类型的用例?

发布于 2024-07-25 08:37:45 字数 594 浏览 11 评论 0原文

在某些情况下,a 的实例 值类型需要被视为 引用类型的实例。 对于 像这样的情况,值类型 实例可以转换为 通过a引用类型实例 过程称为拳击。 当一个值 类型实例已装箱,存储为 分配在堆上和 实例的值被复制到其中 空间。 对此存储的引用是 放置在堆栈上。 盒装值 是一个对象,一个引用类型 包含值的内容 类型实例。

了解 .NET 的通用类型系统

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.

Understanding .NET's Common Type System

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

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

发布评论

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

评论(9

跨年 2024-08-01 08:37:45

一般来说,您通常希望避免对值类型进行装箱。

然而,在极少数情况下这是有用的。 例如,如果您需要以 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.

独夜无伴 2024-08-01 08:37:45

几乎没有充分的理由故意对值类型进行装箱。 几乎总是,对值类型进行装箱的原因是将其存储在某个不支持类型识别的集合中。 例如,旧的 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.

风吹过旳痕迹 2024-08-01 08:37:45

在 .NET 中,装箱通常会在必要时自动发生; 通常当您将值类型传递给需要引用类型的对象时。 一个常见的例子是 string.Format()。 当您将原始值类型传递给此方法时,它们将作为调用的一部分进行装箱。 所以:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

这说明了一个简单的场景,其中值类型 (x) 被自动装箱以传递给需要对象的方法。 一般来说,您希望尽可能避免对值类型进行装箱……但在某些情况下它非常有用。

有趣的是,当您在 .NET 中使用泛型时,值类型在用作类型的参数或成员时不会被装箱。 这使得泛型比旧的 C# 代码(例如 ArrayList)更高效,旧的 C# 代码将所有内容都视为与类型无关的 {object}。 这又增加了使用泛型集合的理由,例如使用 ListDictionary 而不是 ArrayListHashtable

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:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

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> or Dictionary<T,K> over ArrayList or Hashtable.

美胚控场 2024-08-01 08:37:45

我会向您推荐 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

这是我百分百同意的引用

使用堆栈来获取局部值
类型只是一种优化
CLR 代表您执行操作。
值类型的相关特征是
它们具有存在的语义
按值复制,但有时并非如此
他们的释放可以通过以下方式优化
运行时。

在 99% 的应用程序中,开发人员不应该关心为什么值类型在堆栈中而不是在堆中,以及我们在这里可以获得什么性能提升。 Juts 牢记非常简单的规则:

  1. 避免装箱/拆箱
    必要时,使用泛型集合。
    大多数问题并非发生在您
    定义你自己的类型,但是当你
    不正确地使用现有类型
    (由 Microsoft 或您的定义
    同事)
  2. 制定你的价值类型
    简单的。 如果你需要一个结构
    有 10-20 个字段,我想你会
    更好地创建一个类。 想象一下,所有
    每次都会复制该字段
    当你偶尔通过它时
    按值函数...
  3. 我认为它不是很有用
    值类型与引用类型
    里面的字段。 就像结构一样
    字符串和对象字段。
  4. 根据需要定义什么类型
    所需的功能,而不是在哪里
    它应该被存储。 结构体有
    与相比功能有限
    类,所以如果结构不能提供
    所需的功能,例如
    默认构造函数,定义类。
  5. 如果某件事可以执行任何
    使用其他人的数据进行的操作
    类型,它通常被定义为
    班级。 对于结构操作
    应该定义不同的类型
    仅当您可以将一种类型转换为
    其他。 假设你可以添加 int 到
    double 因为你可以将 int 转换为
    双倍的。
  6. 如果某个东西应该是无状态的,那么它就是一个类。
  7. 当您犹豫时,请使用引用类型。 :-)

任何规则都允许在特殊情况下排除,但不要尝试过度优化。

附注
我遇到了一些具有 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

Using the stack for locals of value
type is just an optimization that the
CLR performs on your behalf.
The relevant feature of value types is
that they have the semantics of being
copied by value, not that sometimes
their deallocation can be optimized by
the runtime.

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:

  1. Avoid boxing/unboxing when not
    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)
  2. Make your value types
    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...
  3. I don't think it is very useful to have
    value types with reference type
    fields inside. Like struct with
    String and object fields.
  4. Define what type you need depending on
    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.
  5. If something can perform any
    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.
  6. If something should be stateless, it is a class.
  7. When you are hesitating, use reference types. :-)

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.

洛阳烟雨空心柳 2024-08-01 08:37:45

我认为 C# 中装箱的一个很好的例子出现在非通用集合中,例如 ArrayList

I think a good example of boxing in c# occurs in the non-generic collections like ArrayList.

白色秋天 2024-08-01 08:37:45

一个例子是当方法采用对象参数并且必须传入值类型时。

One example would when a method takes an object parameter and a value type must be passed in.

孤独患者 2024-08-01 08:37:45

下面是一些装箱/拆箱的示例

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing

Below is some examples of boxing/unboxing

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing
眼前雾蒙蒙 2024-08-01 08:37:45

发生这种情况的情况之一是,例如,如果您有需要类型对象参数的方法,并且您正在传入一种基本类型(例如 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.

万劫不复 2024-08-01 08:37:45

该代码

int x = 42;
Console.Writeline("The value of x is {0}", x );

实际上是装箱和拆箱的,因为 Writeline 在内部进行了 int 转换。 为了避免这种情况,您可以

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

注意微妙的错误!

您可以通过将您自己的类型声明为struct来声明您自己的值类型。 想象一下,您声明一个具有大量属性的struct,然后将一些实例放入ArrayList 中。 这当然会限制他们。 现在通过 [] 运算符引用一个,将其转换为类型并设置一个属性。 您只需在副本上设置属性。 ArrayList 中的那个仍然没有修改。

因此,值类型必须始终是不可变的,即使所有成员变量只读,以便它们只能在构造函数中设置,并且没有任何可变类型作为成员。

The code

int x = 42;
Console.Writeline("The value of x is {0}", x );

actually boxes and unboxes because Writeline does an int cast inside. To avoid this you could do

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

Beware of subtle bugs!

You can declare your own value types by declaring your own type as struct. Imagine you declare a struct with lots of properties and then put some instances inside an ArrayList. 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 the ArrayList 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.

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