一个结构是一种值类型,因此,如果我将一个结构分配给另一个结构,则其字段将被复制到第二个结构中。但是,如果结构的某些字段是引用类型,会发生什么呢?
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
为什么
IP
的address1
(字符串,这是引用类型)没有变化?如果我将
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/