我在c#
中做了以下示例 interface IChangeable
{
void Change(params Int32[] array);
}
struct SomeValueType : IChangeable
{
private Int32 m_X;
public SomeValueType(int X)
{
m_X = X;
}
public void Change(params Int32[] array)
{
m_X = array[0];
}
public override string ToString()
{
return String.Format("Crt value of m_X: {0}", m_X);
}
}
在Main:
static void Main(String[] args)
{
SomeValueType someValueType = new SomeValueType(5);
Console.WriteLine(someValueType); // No boxing occured. It showed: 5
Object someRefType = someValueType; // Boxed
Console.WriteLine(someRefType); // Also Shows 5 (from heap)
someValueType.Change(2); // Change Value of x not o's
Console.WriteLine(someValueType + " " + someRefType); // 2 5
((SomeValueType)someRefType).Change(3); // Copies to a temp stack so no change ocuured in o
Console.WriteLine(someRefType); // 5
IChangeable itfStackChange = (IChangeable)someValueType;
itfStackChange.Change(7);
Console.WriteLine(someValueType); // Shows 2 and not 7 ... why?
IChangeable itfChange = (IChangeable)someRefType;
itfChange.Change(1); // Unboxes the value of o, making the value of x 1 boxes o again?
Console.WriteLine(someRefType); // Shows 1
}
现在我想知道当我这样做时会发生什么:
IChangeable itfStackChange = (IChangeable)someValueType; //value was 2 and its still 2
itfStackChange.Change(7);
Console.WriteLine(someValueType);
但是,如果我将struct的定义更改为类,如:
class SomeValueType : IChangeable
它写7而不是2。
答案 0 :(得分:2)
值类型语义是赋值时复制的值。这意味着当您在赋值后更改时,变量将指向不同的对象。
对于引用类型,引用被复制,这意味着当您在赋值后更改时,两个变量都指向同一个对象。
请参阅MSDN上的Value Types and Reference Types。
答案 1 :(得分:0)
结构类型定义实际上定义了两种东西:一种存储位置,以及一种从抽象类System.ValueType
继承的堆对象。堆对象实际上具有相应存储位置类型的一个字段,但是将该存储位置类型的所有成员公开,就像它们自己的一样。对于外部世界,堆类型将表现为类对象;但是,在内部,对this
的引用是对相应存储位置类型的字段的引用。
虽然C#以假装存储位置类型和堆对象类型是同一种方式定义术语“继承”,但这两种类型的行为会有所不同。将值类型转换为它表示的接口将生成一个新的堆对象,该对象包含已转换的值类型的公共和私有字段的副本,然后返回对该新实例的引用。结果引用将显示引用语义,因为它将是一个引用。
如果将堆对象和值类型存储位置视为存在于不同的Universe中,并且识别必须将值从一个Universe复制到另一个Universe的情况,则会发现这样的模型将准确地预测事物将如何表现。