关于C#:修改结构变量


Modify struct variable

本问题已经有最佳答案,请猛点这里访问。

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

MWE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;

public class Program
{
    public struct Point
    {
        public int x, y;

        public Point(int p1, int p2)
        {
            x = p1;
            y = p2;
        }
    }

    public static void PrintPoint(Point p)
    {
        Console.WriteLine(String.Format("{{x: {0}, y: {1}}}", p.x, p.y));
    }

    public static void Main()
    {
        var c = new Point(5, 6);
        PrintPoint(c);                                          // {x: 5, y: 6}

        c.x = 4;  // this works
        PrintPoint(c);                                          // {x: 4, y: 6}

        var d = new Dictionary<string, Point>()
        {
            {"a", new Point(10, 20) },
            {"b", new Point(30, 40) }
        };

        foreach (Point p in d.Values)
        {
            PrintPoint(p);  // this works
        }

        PrintPoint(d["a"]); // this works                       // {x: 10, y: 20}

        Console.WriteLine(d["a"].x.ToString());  // this works  // 10

        // d["a"].x = 2; // why doesn't this work?
    }
}

当结构变量在字典中但不能再更改它们时,我怎么能访问它呢?我该如何更换它们?


你想做的事情有几个问题。

在99.9999999999%的情况下,结构应该是只读的。请参阅Microsoft设计指南https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/struct

X DO NOT define mutable value types.

Mutable value types have several problems. For example, when a
property getter returns a value type, the caller receives a copy.
Because the copy is created implicitly, developers might not be aware
that they are mutating the copy, and not the original value. Also,
some languages (dynamic languages, in particular) have problems using
mutable value types because even local variables, when dereferenced,
cause a copy to be made.

您也不应该改变用作字典键的对象。字典是基于散列值的,如果更改键的字段,您将更改其散列值。请参阅:https://stackoverflow.com/a/3007334/4415493

The Dictionary type makes no attempt to protect against
the user modifying the key used. It is purely left up to the developer
to be responsible in not mutating the key.

If you think about this a bit this is really the only sane route that
Dictionary can take. Consider the implication of doing an
operation like a memberwise clone on the object. In order to be
thorough you'd need to do a deep clone because it will be possible for
an object referenced in the key to also be mutated and hence affect
the hash code. So now every key used in the table has it's full object
graph cloned in order to protect against mutation. This would be both
buggy and possibly a very expensive operation.


字典值是一个点对象。因此,可以用新的点对象更新键。

1
2
3
4
5
6
7
8
9
10
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());