最近,我在互联网上发现了一个问这个问题的帖子,我试图找出但不确定。
我猜这个问题与拳击和拆箱有关:
public readonly object counter = new Counter();
此行将Counter装入堆,而counter指向它。
((Counter)riddle.counter)
此行从堆中取消装箱。
每次从堆中取消装箱的数据都与原点相同。因此,A行不会影响B行,因为它们都是从堆中检索的,并且是Counter的两个不同实例。
是吗?抱歉我的英语不好。
public void WantToKnow()
{
var riddle = new Riddle();
((Counter)riddle.counter).Increment(); // Line A
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
// Why the output is 0?///////////////////
}
struct Counter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}
答案 0 :(得分:1)
首先,这是我几乎在所有情况下都试图避免可变结构的一个很好的例子。虽然你通常可以预测如果你给予足够的重视会发生什么,但很容易错过一个副本,这会让一切都搞砸。如果你保持所有结构不变,生活就会更简单。
对于您的问题:是的,您正在拆箱,这会创建计数器的副本。更改该副本不会影响其他任何内容。 (没有复制就有IL到unbox,但C#从不使用它。)
你可以通过让你的计数器实现一个Increment
操作的接口来实现这项功能。此时,您可以转换为界面而不是值类型,这意味着它不会取消装箱。然后,您的Increment
操作会修改框内的值,这意味着您可以再次获取该值。这是一个完整的例子:
using System;
class Program
{
static void Main()
{
var riddle = new Riddle();
((ICounter)riddle.counter).Increment();
Console.WriteLine(((Counter)riddle.counter).Count); // Line B
}
}
interface ICounter
{
void Increment();
}
struct Counter : ICounter
{
private int x;
public void Increment() { this.x++; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}
答案 1 :(得分:0)
因为struct是值类型 - 你可以使用“class counter”struct struct Counter“
或使用以下解决方案
原因 :((计数器)riddle.counter).Count被视为struct的另一个副本而不是ref类型。所以它显示初始值0
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
var riddle = new Riddle();
Console.WriteLine(((Counter)riddle.counter).Increment());
///////////////////////////////////////////
Console.WriteLine(((Counter)riddle.counter).Count);
// Why the output is 0?///////////////////
}
}
struct Counter
{
private int x;
//Change is here
public int Increment() { this.x++; return this.x; }
public int Count { get { return this.x; } }
}
class Riddle
{
public readonly object counter = new Counter();
}