C# 修改结构变量

C# 修改结构变量,c#,C#,假设我有一个公共int的x和y的结构点。我想更改一个值,我可以。但一旦我把它储存在字典里,我就不能再这样做了。为什么? MWE: 使用系统; 使用System.Collections.Generic; 公共课程 { 公共结构点 { 公共整数x,y; 公共点(int p1、int p2) { x=p1; y=p2; } } 公共静态无效打印点(点p) { WriteLine(String.Format(“{{x:{0},y:{1}}}”,p.x,p.y)); } 公共静态void Main() {

假设我有一个公共int的x和y的结构点。我想更改一个值,我可以。但一旦我把它储存在字典里,我就不能再这样做了。为什么?

MWE:

使用系统;
使用System.Collections.Generic;
公共课程
{
公共结构点
{
公共整数x,y;
公共点(int p1、int p2)
{
x=p1;
y=p2;
}
}
公共静态无效打印点(点p)
{
WriteLine(String.Format(“{{x:{0},y:{1}}}”,p.x,p.y));
}
公共静态void Main()
{
var c=新点(5,6);
打印点(c);//{x:5,y:6}
c、 x=4;//这是可行的
打印点(c);//{x:4,y:6}
var d=新字典()
{
{“a”,新的第(10,20)点},
{“b”,新的点(30,40)}
};
foreach(d.值中的p点)
{
PrintPoint(p);//这很有效
}
PrintPoint(d[“a”]);//这是有效的//{x:10,y:20}
Console.WriteLine(d[“a”].x.ToString());//这很有效//10
//d[“a”].x=2;//为什么不起作用?
}
}

为什么我可以访问字典中的结构变量,但不能再更改它们?如何更改它们?

您的字典值是点对象。因此,可以使用新的点对象更新关键点

Right Way (Update):
            d["a"]= new Point(5, 20);
            PrintPoint(d["a"]);
            Console.WriteLine(d["a"].x.ToString());

Round About: (Remove and Add)
            d.Remove("a");
            d.Add("a", new Point(2, 20));
            PrintPoint(d["a"]);
            Console.WriteLine(d["a"].x.ToString()); 

你所做的有几件事是错误的

在99.99999999%的情况下,结构应该是只读的。请参阅Microsoft设计指南

X不定义可变值类型

可变值类型有几个问题。例如,当 属性getter返回一个值类型,调用方接收一个副本。 因为副本是隐式创建的,所以开发人员可能不知道 他们正在改变副本,而不是原始值。也, 某些语言(特别是动态语言)在使用时遇到问题 可变值类型,因为即使是局部变量,在取消引用时, 使副本被复制

您也不应该改变用作字典键的对象。字典是基于散列值的,如果您更改密钥的字段,您将更改其散列值。见:

字典类型不试图防止 用户正在修改所使用的密钥。这完全由开发人员决定 负责不改变密钥

如果你想一想,这真的是唯一明智的选择 这本字典可以用。考虑做某事的含义 操作类似于对象上的memberwise克隆。为了 你需要做一个深度克隆,因为它可以 键中引用的对象也将发生变异,从而影响 散列码。所以现在表中使用的每个键都有它的完整对象 为了防止变异而克隆的图形。这两者都是 马车和可能是一个非常昂贵的操作


请参阅:因为
d[“a”]
返回一个临时副本,而您没有将其存储在任何地方。修改临时文件没有意义,因为编译器会抱怨“不工作”。该投诉的文本是相关的。解决此问题的一种方法是为字典项分配一个新的
,该点具有新的
x
值和相同的
y
值:
d[“a”]=新点(2,d[“a”].y)从设计角度看的一条注释:如果您要有一个构造函数,它接受用于设置属性(本例中为字段)的值,那么将构造函数参数名称与属性名称相同对类/结构的客户机很有帮助,这样他们就可以理解所设置的内容。例如:
publicpoint(intx,inty){…}
除非我漏掉了什么,否则OP不是在变异字典键,是吗?不是,但OP正在尝试更改存储在该键下的项-他得到了一个copy@HansKesting对,但这个答案的一半是关于不变异用作键的对象…第一部分有意义(+1),但我并不是想改变答案。我想我的问题应该以重复的形式结束,但我现在要接受这一点,因为我的强迫症部分希望看到1991年的分数变成2000分:P-不过,感谢你真正的帮助!
Right Way (Update):
            d["a"]= new Point(5, 20);
            PrintPoint(d["a"]);
            Console.WriteLine(d["a"].x.ToString());

Round About: (Remove and Add)
            d.Remove("a");
            d.Add("a", new Point(2, 20));
            PrintPoint(d["a"]);
            Console.WriteLine(d["a"].x.ToString());