一个结构是一种值类型,因此,如果我将一个结构分配给另一个结构,则其字段将被复制到第二个结构中。但是,如果结构的某些字段是引用类型,会发生什么呢?

public struct MyIPEndPoint
{
    public String IP;
    public UInt16 Port;

    public MyIPEndPoint(String ipAddress, UInt16 portNumber)
    {
        IP = ipAddress;
        Port = portNumber;
    }

    public override string ToString()
    {
        return IP+":"+Port;
    }
}

...

static int Main(string[] args)
{
    MyIPEndPoint address1 = new MyIPEndPoint("127.0.0.1", 8080);
    MyIPEndPoint address2 = address1;

    address2.IP = "255.255.255.255";
    address2.Port = 9090;

    Console.WriteLine(address1);
    Console.WriteLine(address2);
}

输出为:
127.0.0.1:8080
255.255.255.255:9090

为什么IPaddress1(字符串,这是引用类型)没有变化?
如果我将string替换为IPAddress以表示MyIPEndPoint中的IP,则会发生相同的行为:尽管IPAddress是一个类(即引用类型),但它不能充当引用类型。为什么?

的确,如果我使用新的简单类string包装表示IP的MyIP,则行为会改变。
public class MyIP
{
    public string IpAsString;

    public MyIP(string s)
    {
        IpAsString = s;
    }
    public override string ToString()
    {
        return IpAsString;
    }
}

当然,您还应该通过以下方式调整MyIPEndPoint结构:
public struct MyIPEndPoint
{
    public MyIP IP;   // modification
    public UInt16 Port;

    public MyIPEndPoint(String ipAddress, UInt16 portNumber)
    {
        IP = new MyIP(ipAddress);   // modification
        Port = portNumber;
    }

    public override string ToString()
    {
        return IP+":"+Port;
    }
}

最后,在Main中,我仅更改了一条语句:
MyIPEndPoint address1 = new MyIPEndPoint("127.0.0.1", 8080);
MyIPEndPoint address2 = address1;

address2.IP.IpAsString = "255.255.255.255";   // modification
address2.Port = 9090;

Console.WriteLine(address1);
Console.WriteLine(address2);

现在的输出是:
255.255.255.255:8080
255.255.255.255:9090

在第一种情况下,我一直期待此输出。
为什么在第一种情况下,引用的行为不符合预期?

最佳答案

您已经正确理解,对于结构,address1和address2不是同一对象。值已复制。但是,对于现场而言,这是重新分配的简单情况。它与字符串是引用类型,任何特殊规则或不变性的暗示无关。您只需为属性或字段重新分配了另一个值即可。

someStruct.SomeString = "A";
anotherStruct = someStruct;
anotherStruct.SomeString = "B"; // would never affect someStruct

您已经在本示例中覆盖了引用。在短时间内,两个结构的字段包含相同的引用这一事实并不重要。在第二个示例中,您做了一些非常不同的事情。
someStruct.IP.SomeString = "A";
anotherStruct = someStruct;
anotherStruct.IP.SomeString = "B";

在这种情况下,IP的值未更改。 IP状态的一部分已更改。每个结构的字段仍引用相同的IP。

简单来说
var foo = new Foo(); // Foo is class
var other = foo;
// other and foo contain same value, a reference to an object of type Foo
other = new Foo(); // was foo modified? no!

int x = 1;
int y = x;
y = 2; // was x modified? of course not.

string s = "S";
string t = s;
t = "T"; // is s "T"? (again, no)

变量和字段包含值。对于类,这些值是对对象的引用。两个变量或字段可以拥有相同的引用,但这并不意味着这些变量本身已链接在一起。它们无论如何都没有连接,只是拥有一个共同的值(value)。当您为一个变量或字段替换值时,另一变量不受影响。

不在特定主题上,但是值得注意的是,许多人将可变结构视为邪恶。其他人则不太持相同观点,或者至少不那么虔诚。 (但是,还值得注意的是,如果Address是一个类,那么address1和address2将具有相同的值(对Address对象的引用),并且只要address1和Address1都不对Address1的状态进行修改,就可以通过address2对其进行修改或地址2本身已重新分配。)

如果这是代码的实际表示形式,那么就值得对mutable structs进行一些研究,因此您至少应充分了解您可能会遇到的各种陷阱。

关于c# - 包含引用类型的结构,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9203516/

10-17 02:47