C# 区分值类型和引用类型。值类型(结构和原始类型,string1 除外)按值传递(复制),而引用类型(类)本质上是花哨的指针。 (顺便说一句,在 IDE 中,如果您将鼠标悬停在变量上,它会告诉您它是类还是结构)。
因此,请记住这一点,这就是您的代码的作用:
class A // reference type
{
public Int32 X = 10; // with a value type field
}
class B // reference type
{
// The ctor takes in a value type parameter; a copy of the
// value is passed in (pretty much like in C++)
public B(Int32 x)
{
Y = x; // this now contains its own copy
}
// value type PROPERTY -- see below
public Int32 Y { get; set; }
}
所以,在你的主要方法中,当你这样做时
A a = new A();
B b = new B(a.X);
b.Y 与 a.X 没有连接,因为只要 a.X 被计算,构造函数就会得到 a.X 的副本。
您可以做的最简单的事情是让 B 的构造函数接受 A 类型的参数,然后在内部存储对 A 的引用:
class B
{
private A _a;
public B(A a) // a is passed in by reference
{
_a = a;
}
public Int32 Y {
get => _a.X;
set => _a.X = value;
}
}
当你这样做时
A a = new A();
B b = new B(a);
a 指代b 内部和外部的同一个对象。更改a.X 会影响调用b.Y 的结果。
你也可以直接暴露a:
class B
{
public B(A a)
{
A = a;
}
public A A { get; set; }
}
然后在main()中:
A a = new A();
B b = new B(a);
Console.WriteLine(b.A.X); // 10
a.X = 11;
Console.WriteLine(b.A.X); // 11
关于属性的说明
您应该注意字段和属性之间的区别。字段是数据成员,就像在 C++ 中一样。 property 只是编译器在后台生成的 get/set 方法对的一些语法糖。大致相当于这样:
class B
{
private A _a;
public B(A a)
{
_a = a;
}
public A GetA() {
return _a;
}
public void SetA(A value) {
_a = value;
}
}
在这种情况下,由于 A 是一个引用类型,它通过 getter 的引用返回。但是现在假设 A 被声明为一个结构(一个值类型)。然后 getter 会返回一个副本。这有时会导致 C# 初学者不明显的问题。
struct A // value type
{
public Int32 X; // with a value type field
public A(Int32 x) { X = x; }
}
如果 A 是一个结构,并且你尝试这样做
b.A.X = 11;
你会得到一个编译器错误:“Cannot modify the return value of 'b.A.X' because it is not a variable”。
原因是因为b.A返回了一个副本,所以如果你在上面更改X,那行之后的更改就会丢失。您必须替换整个 A 实例:
A a = new A(10); // struct
B b = new B(a); // class containing a struct
Console.WriteLine(b.A.X); // 10
a.X = 11;
Console.WriteLine(b.A.X); // 10 - because A is a value type now
b.A = new A(11); // setting a property on B works as expected,
// but you can't do b.A.X = 11
Console.WriteLine(b.A.X); // 11
附:在 C# 中,您通常会编写 int 而不是 Int32。
1string 是一个引用类型,但是,它是不可变的(所有“修改”字符串的操作都返回单独的string 实例)。