C# makes a distinction between value types and reference types. Value types (structs and primitive types, except string1) are passed around by value (a copy is made), while reference types (classes) are essentially fancy pointers. (BTW, in an IDE, if you hover your mouse over a variable, it will tell you if it's a class or a struct).
So, keeping that in mind, this is what your code does:
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; }
}
So, in your main method, when you do
A a = new A();
B b = new B(a.X);
b.Y has no connection to a.X because the constructor gets a copy of a.X as soon as a.X is evaluated.
The simplest thing you can do is to have the constructor of B accept a parameter of type A instead, and then store a reference to A internally:
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;
}
}
Now when you do
A a = new A();
B b = new B(a);
the a refers to the same object both inside and outside of b. Changing a.X will affect the result of invoking b.Y.
You can also expose a directly:
class B
{
public B(A a)
{
A = a;
}
public A A { get; set; }
}
Then in 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
A note about properties
You should be aware of the difference between fields and properties. Fields are data members, just like in C++. A property is just some syntactic sugar for a get/set method pair that's generated behind the scenes by the compiler. It's roughly equivalent to something like this:
class B
{
private A _a;
public B(A a)
{
_a = a;
}
public A GetA() {
return _a;
}
public void SetA(A value) {
_a = value;
}
}
In this case, since A is a reference type, it's returned by reference from the getter. But suppose now that A was declared to be a struct (a value type). Then the getter would return a copy. This sometimes causes a problem that's not obvious to C# beginners.
struct A // value type
{
public Int32 X; // with a value type field
public A(Int32 x) { X = x; }
}
If A is a struct, and you try to do
b.A.X = 11;
you'll get a compiler error: "Cannot modify the return value of 'b.A.X' because it is not a variable".
The reason is because b.A returns a copy, so if you changed X on it, the change would be lost after that line. You have to replace the entire A instance instead:
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
P.S. In C#, you would typically write int instead of Int32.
1 string is a reference type, however, it's immutable (all operations that "modify" strings return separate string instances).