How to Assign by "Reference" to a Class Field in C#

How do I assign by reference to a class field in C#?

No. ref is purely a calling convention. You can't use it to qualify a field. In Z, _Example gets set to the value of the string reference passed in. You then assign a new string reference to it using +=. You never assign to example, so the ref has no effect.

The only work-around for what you want is to have a shared mutable wrapper object (an array or a hypothetical StringWrapper) that contains the reference (a string here). Generally, if you need this, you can find a larger mutable object for the classes to share.

 public class StringWrapper
{
public string s;
public StringWrapper(string s)
{
this.s = s;
}

public string ToString()
{
return s;
}
}

public class X
{
public X()
{
StringWrapper example = new StringWrapper("X");
new Z(example)
System.Diagnostics.Debug.WriteLine( example );
}
}

public class Z
{
private StringWrapper _Example;
public Z( StringWrapper example )
{
this._Example = example;
this._Example.s += " (Updated By Z)";
}
}

C# - Assign an object's field as reference to another object's field (like a pointer)

In my opinion the easiest way to achieve what you want is to use a Func<string> to retrieve reference values:

class Person
{
private Func<string> _fullName;
public string FullName { get => _fullName(); set => _fullName = () => value; }

public void SetFullNameRef(Func<string> value)
{
_fullName = value;
}
}


static void Main(string[] args)
{
var person01 = new Person() { FullName = "Steve" };
var person02 = new Person() { FullName = "Mr. S" };
var person03 = new Person() { FullName = "Mister Steve" };

person02.SetFullNameRef(() => person01.FullName);
person03.SetFullNameRef(() => person02.FullName);

person01.FullName = "Mr. Steve Jobs";

Console.WriteLine(person01.FullName); // Mr. Steve Jobs
Console.WriteLine(person02.FullName); // Mr. Steve Jobs
Console.WriteLine(person03.FullName); // Mr. Steve Jobs
}

Or write it like that:

class Person
{
private Func<string> _fullName;
public string FullName { get => _fullName(); set => _fullName = () => value; }
public Func<string> RefFullName { get => () => _fullName(); set => _fullName = () => value(); }
}


static void Main(string[] args)
{
var person01 = new Person() { FullName = "Steve" };
var person02 = new Person() { FullName = "Mr. S" };
var person03 = new Person() { FullName = "Mister Steve" };

person02.RefFullName = person01.RefFullName;
person03.RefFullName = person02.RefFullName;

person01.FullName = "Mr. Steve Jobs";

Console.WriteLine(person01.FullName); // Mr. Steve Jobs
Console.WriteLine(person02.FullName); // Mr. Steve Jobs
Console.WriteLine(person03.FullName); // Mr. Steve Jobs
}

How to create a reference to a value-field

Well... there is a very contort way :) of course.
That is, using reflection!
You cannot get the address of a field, but we can use reflection.

Reflection is slower than accessing directly a field, i warn you.
And really, accessing private fields of other classes is a really bad practice!
Is however useful sometime for some dirty hacks when you don't have control of code written by other people.

Here the example, but i keep saying, it is not a good practice, is here only for curiosity and for educational purposes!

Fine another way to access your field, using properties or using a class that modify your properties.

// Our FieldReference class that internally uses reflection to get or set a field value.
public class FieldReference<T>
{
private object ownerObject;
private FieldInfo fieldInfo;

public FieldReference(object ownerObject, string fieldName)
{
this.ownerObject = ownerObject;
this.fieldInfo = ownerObject.GetType().GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}

public FieldReference(object ownerObject, FieldInfo fieldInfo)
{
this.ownerObject = ownerObject;
this.fieldInfo = fieldInfo;
}

public T Value
{
get { return (T)this.fieldInfo.GetValue(this.ownerObject); }
set { this.fieldInfo.SetValue(this.ownerObject, value); }
}
}

// Our dummy class
public class MyClass
{
// Our field we want to expose.
private int myField;

public MyClass(int value)
{
this.myField = value;
}

// Just a function we use to print the content of myField.
public override string ToString()
{
return this.myField.ToString();
}
}

class Program
{
public static void Main()
{
// We create our class.
MyClass mc = new MyClass(5);

// We print field value, should be 5 :)
Console.WriteLine(mc.ToString());

// We create our field reference
FieldReference<int> fieldref = new FieldReference<int>(mc, "myField");

// We set the value using field reference.
// Note, we accessed a private field :)
fieldref.Value = 100;

// Now we print the value, should be 100!
Console.WriteLine(mc.ToString());

Console.ReadLine();
}
}

C# assign property by reference

Both your custom class, NewClass, and List<T> are reference types.

From Microsoft's documentation on Reference Types:

There are two kinds of types in C#: reference types and value types. Variables of reference types store references to their data (objects), while variables of value types directly contain their data. With reference types, two variables can reference the same object; therefore, operations on one variable can affect the object referenced by the other variable. With value types, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other (except in the case of in, ref and out parameter variables; see in, ref and out parameter modifier).

[emphasis mine]

So, to accomplish what you want all you'd have to do is assign each child's NewClassList property to its parent's NewClassList.

var firstParent = new ParentClass
{
NewClassList = new List<NewClass>(),
ChildClassList = new List<ChildClass>()
};
firstParent.ChildClassList.Add(new ChildClass
{
NewClassList = firstParent.NewClassList
});
firstParent.ChildClassList.Add(new ChildClass
{
NewClassList = firstParent.NewClassList
});
firstParent.NewClassList.Add(new NewClass
{
Name = "Hugh Mann",
Age = 48
});
//firstParent and both children now contain Hugh Mann.

firstParent.ChildClassList[0].NewClassList.Add(new NewClass
{
Name = "Sillius Soddus",
Age = 43
});
//firstParent and both children now contain Sillius Soddus.

firstParent.ChildClassList[1].NewClassList.Add(new NewClass
{
Name = "Joanna Dance",
Age = 62
});
//firstParent and both children now contain Joanna Dance.

firstParent.NewClassList[0].Age = 23;
//Hugh Mann now has an age of 23 in firstParent and its children

If you were to assign a different list to either the parent or the child they would no longer be referencing the same list. Changes to one list would not occur on the other as they are referencing completely different lists.

var firstParent = new ParentClass
{
NewClassList = new List<NewClass>(),
ChildClassList = new List<ChildClass>()
};
firstParent.ChildClassList.Add(new ChildClass
{
NewClassList = firstParent.NewClassList
});

firstParent.ChildClassList[0].NewClassList.Add(new NewClass
{
Name = "Sillius Soddus",
Age = 43
});
//firstParent and its child now contain Sillius Soddus.

firstParent.NewClassList = new List<NewClass>
{
new NewClass
{
Name = "Hugh Mann",
Age = 22
}
};
//firstParent.NewClassList now references a totally different list. It contains Hugh Mann, while firstParent.ChildClassList[0] contains Sillius Soddus.

firstParent.NewClassList.Add(new NewClass
{
Name = "Ian D. Dark",
Age = 33
});
//firstParent.NewClassList now contains Hugh Mann and Ian D. Dark. Since firstParent.ChildClassList[0] references a totally different list it still only contains Sillius Soddus.

Setting a ref to a member field in C#

There are really two issues here.

One, as the other posters have said, you can't strictly do what you're looking to do (as you may be able to with C and the like). However - the behavior and intent are still readily workable in C# - you just have to do it the C# way.

The other issue is your unfortunate attempt to try and use strings - which are, as one of the other posters mentioned - immutable - and by definition get copied around.

So, having said that, your code can easily be converted to this, which I think does do what you want:

public class End
{
public StringBuilder parameter;

public End(StringBuilder parameter)
{
this.parameter = parameter;
this.Init();
Console.WriteLine("Inside: {0}", parameter);
}

public void Init()
{
this.parameter.Clear();
this.parameter.Append("success");
}
}

class MainClass
{
public static void Main(string[] args)
{
StringBuilder s = new StringBuilder("failed");
End e = new End(s);
Console.WriteLine("After: {0}", s);
}
}

Assign value of a reference property to a variable

Wrap value with the reference type

public class CanUpdate
{
public bool Value { get; set; }
}

Then

public class B
{
private readonly CanUpdate _canUpdate;

public B(CanUpdate value)
{
_canUpdate = value;
}

private void UpdateValue()
{
_canUpdate.Value = true;
}
}

Class A will "see" value changed by class B

public class A
{
private CanUpdate CanUpdate;

public A()
{
CanUpdate = new CanUpdate { Value = false };
}

public void DoSomething()
{
Console.WriteLine(CanUpdate.Value); // false

var b = new B(CanUpdate);
b.UpdateValue();

Console.WriteLine(CanUpdate.Value); // true
}
}

Having own dedicated type for a value improves readability and makes code more comprehensible for others.

How can I create a reference member variable in C# like in C++


int is just a placeholder for another class here

Whoa there! int is not just "another class". int is a value type. You can't have a field that's a reference to it. You can have a ref parameter. In C#7 you can have ref returns and locals, but still not fields.

In the CLR, int is critically different from classes in exactly the area we're talking about here. x is an int on what we'll figuratively call "the stack", since I don't feel like looking up how they actually implemented it. In C, I seem to recall describing that as a stack variable:

int x = 0;

List<T> is a class. y, here, is a "stack variable" which is a rebindable reference to an object on the "heap":

var y = new List<int>();

If you're talking about sharing references to reference types -- any class -- in C# that's easy: It's always a reference.

public class C {
// x is passed by value. It is the value of a reference. Seriously, it is.
public C(List<String> x) {
List = x;
}
public List<String> List { get; set; }
}

...

var list = new List<String>();
var x = new C(list);
var y = new C(list);

x.List and y.List are the same object, at least until you assign a new object to one of them -- C# references, unlike C++ references (at least as of C++98; I haven't kept up since 2006) are "rebindable".

The way to do this is to write a simple class with an int property, and share a reference to an instance of that. where T : struct restricts T to be a struct rather than a class. In CLR-land, that means "value type" rather than "reference type".

public class Reference<T> where T : struct
{
public Reference(T t) {
Value = t;
}

public T Value { get; set; }
}

class MyClass
{
MyClass(Reference<int> ref)
{
_ref = ref;
}
Reference<int> _ref;
}

Why did C# take away the functionality to create reference member variables?

They didn't "take it away"; they didn't abduct an infant C++ compiler and cut its toes off. They just didn't think it was a good idea to do that in C#, and they were right. C# isn't C and it isn't meant to be C. Dennis Ritchie designed C to be used by people like Ken Thompson; Anders Hejlsberg explicitly designed C# to be used by the rest of us, who are much more easily confused.

This is built deeply into .NET:

The CLR type system however does not allow for fields that are aliases to other variables

(That's an old essay; C#7 now does support the additional uses of ref that the CLR supported all along).

New C# programmers already have more than enough trouble with ref and reference types. Just recently I saw code in a question here much like this:

public void F(ref List<int> x) { ... }

The fellow who wrote that code just wanted to pass in a List<int> without creating an expensive copy of it.

How do I assign reference field

Unfortunately, there is no native way to store a reference to a variable in C#. Luckily, there are many ways to have b's X object reference stay in sync with a's X object reference.

First, the classes:

  public class SomeClass
{
public X x;
}

public class X
{
public int i; // I added this int to verify which X object we're working with.
public X(int i)
{
this.i = i;
}
}

Scenario 1: If you need to reference a new X object.

Option 1: If a and b need to be different SomeClass objects, you can simply update b's X object reference to a's X object reference.

  SomeClass a = new SomeClass();
SomeClass b = new SomeClass();

a.x = new X(1);
b.x = a.x;
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:1, b.x.i:1
a.x = new X(2);
b.x = a.x;
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:2, b.x.i:2

Option 2: If b doesn't need to be different than a, have b reference the same SomeClass object that a does.

  SomeClass a = new SomeClass();
SomeClass b = a;

a.x = new X(1);
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:1, b.x.i:1
a.x = new X(2);
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:2, b.x.i:2

Scenario 2: If you only need to modify an internal value of the X object.

Since a.x is the same X object as b.x, you can modify that object using either reference and view that change using the other reference.

  SomeClass a = new SomeClass();
SomeClass b = new SomeClass();

a.x = new X(1);
b.x = a.x;
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:1, b.x.i:1
a.x.i = 2;
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:2, b.x.i:2
b.x.i = 3;
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:3, b.x.i:3

Scenario 3: If you want a different class to always have easy access to a's X object.

New class:

  public class SomeClass2
{
private SomeClass someClass;
public X x { get { return someClass.x; } }
public SomeClass2(SomeClass sc)
{
someClass = sc;
}
}

Using the new class:

  SomeClass a = new SomeClass();
SomeClass2 b = new SomeClass2(a);

a.x = new X(1);
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:1, b.x.i:1
a.x = new X(2);
Console.WriteLine($"a.x.i:{a.x.i}, b.x.i:{b.x.i}"); // a.x.i:2, b.x.i:2

Scenario 4: If you want a local alias to a.x.

  SomeClass a = new SomeClass();

Func<X> func = () => a.x; // "func()" is now essentially an alias of "a.x"
a.x = new X(1);
Console.WriteLine($"a.x.i:{a.x.i}, func().i:{func().i}"); // a.x.i:1, func().i:1
a.x = new X(2);
Console.WriteLine($"a.x.i:{a.x.i}, func().i:{func().i}"); // a.x.i:2, func().i:2

Scenario 5: If you need to use the same class and have b.x always reference the same object as a.x.

You can use a Func<X> member of your class to act like similarly to a variable reference. This works but I don't necessarily recommend doing it because it is not intuitive and can cause confusion.

The class:

  public class SomeClass3
{
public Func<X> x;
}

Using the class:

  SomeClass3 a = new SomeClass3();
SomeClass3 b = new SomeClass3();

X x1 = new X(1);
a.x = () => x1;
b.x = () => a.x();
Console.WriteLine($"a.x().i:{a.x().i}, b.x().i:{b.x().i}"); // a.x().i:1, b.x().i:1
X x2 = new X(2);
a.x = () => x2;
Console.WriteLine($"a.x().i:{a.x().i}, b.x().i:{b.x().i}"); // a.x().i:2, b.x().i:2


Related Topics



Leave a reply



Submit