使用的情况下拳击值的类型在C#?
-
06-07-2019 - |
题
在有些情况下,当一个实例 值类型需要被视为一个 实例引用类型。 对于 像这样的情况,值的类型 实例可以被转换成 参照类型的实例通过 处理所谓的拳击。当一个值 类型的实例是盒装、储存是 在堆上分配和 实例的价值是拷贝到这 空间。一个参考这个存储是 放在栈。装箱的价值 是一个对象,基准类型 包含的内容的价值 类型的实例。
在 维基百科 有一个例子Java。但在C#什么某些情况下,一个人必须要框值的类型?或者一个更好的/相似的问题是,为什么一个想要保存一个值型堆上(装箱)而不是在栈?
解决方案
通常,您通常希望避免装箱值类型。
但是,很少有这种情况有用。例如,如果您需要定位1.1框架,则无法访问泛型集合。在.NET 1.1中使用集合需要将您的值类型视为System.Object,这会导致装箱/取消装箱。
在.NET 2.0+中仍然存在这种情况。只要您想利用所有类型(包括值类型)可以直接作为对象这一事实,您可能需要使用装箱/拆箱。这有时很方便,因为它允许您在集合中保存任何类型(通过在通用集合中使用对象而不是T),但一般来说,最好避免这种情况,因为您正在失去类型安全性。但是,经常发生拳击的一种情况是,当你使用反射时 - 反射中的许多调用在处理值类型时需要装箱/拆箱,因为事先不知道类型。
其他提示
几乎没有充分的理由故意选择值类型。包装值类型的原因几乎总是将其存储在一些非类型感知的集合中。例如,旧的 ArrayList 是一个集合对象,它们是引用类型。收集整数的唯一方法是将它们作为对象封装并将它们传递给ArrayList。
如今,我们有通用集合,所以这不是一个问题。
拳击通常会在.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)更有效,它将{object}视为与类型无关的所有内容。这增加了使用泛型集合的另一个原因,例如List<T>
或Dictionary<T,K>
over ArrayList
或Hashtable
。
我会推荐你2个不错的文章的埃里克利珀特
http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx
这里是报价,我100%的同意
使用堆为你的价值 类型只是一个优化的 CLR执行您的代表。相关的功能价值的类型 他们的语义是 复制的价值,而不是有时 他们的释放可以通过优化 运行时。
在99%的应用程序开发者应该不关心你为什么值类型是在堆,而不是在堆和什么样的性能增加我们在这里。伸心中已有非常简单的规则:
- 避免拳/拆箱的时候不 有必要,可使用仿制药的藏品。大多数问题发生不当你 定义自己的类型,但是当你 使用现有类型的不正确 (Microsoft定义的或者你的 同事)
- 让你的价值的类型 简单的。如果你需要有一个结构 与10-20个领域,我想你'ld 更好地创造一类。想象一下,所有的 这一领域将复制的每个时间 当你偶尔传递一个 功能的价值...
- 我不认为这是非常有用 值类型的参照类型 领域内。像的结构与 String和对象领域。
- 定义是什么类型取决于你需要的 所需的功能,不在那里 它应该被存储。结构有 限制功能的比较 课程,因此如果结构不能提供 所需的功能,像 默认的构造,定义类。
- 如果有什么可以执行的任何 行动数据的其他 类型,它通常被定义为一个 类。对于结构与行动 不同类型的定义应该 如果你只能投一类型的 另一个。说你可以添加int 双因为你可以投int 一倍。
- 如果事情应该是无国籍,这是一类。
- 当你正犹豫不决,使用的基准类型。:-)
任何规则允许排除在特殊情况下,但不要尝试过优化。
p.s.我遇到了一些ASP.NET 开发人员2-3年的经验,谁不知道之间的差堆和堆。:-(我不会租用这样一个人如果我是个采访但并不是因为拳/拆箱可能是一个瓶颈中的任何ASP.NET 网站是我见过。
我认为c#中装箱的一个很好的例子出现在非泛型集合中,如 ArrayList 。
一个例子是当一个方法接受一个object参数并且必须传入一个值类型时。
以下是装箱/拆箱的一些例子
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
发生这种情况的一种情况是,例如,如果您有方法期望类型为object的参数,并且您正在传递其中一种基本类型,例如int。或者,如果将参数定义为int类型的“ref”。
代码
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
来声明自己的值类型。想象一下,您声明了一个包含大量属性的ArrayList
,然后将一些实例放在[]
中。这当然是他们的盒子。现在通过readonly
运算符引用一个,将其转换为类型并设置属性。您只需在副本上设置属性即可。 <=>中的那个仍未修改。
由于这个原因,值类型必须始终是不可变的,即使所有成员变量<=>,以便它们只能在构造函数中设置,并且没有任何可变类型作为成员。