1

I have one instance of ClassA that is passed as a ref to constructor of ClassB. Does the instance of ClassB now always have the access to the newest updated version of the passed instance of ClassA?

public class ClassA {
    private int variableA = 0;
    public ClassA() { }
    public void Change(int newValue) {
        variableA = newValue;
    }
}

public class ClassB {
    public ClassA classA;
    public ClassB(ref ClassA refClassA) {
        classA = refClassA;
    }
    public void Print() {
        Console.WriteLine(classA.variableA);
    }
}

static void Main() {
    ClassA classA = new ClassA();
    ClassB classB = new ClassB(ref classA);
    classB.Print(); // 0
    classA.Change(50);
    classB.Print(); // 50?
}

I've read what I found on the internet but the only usage I've found was to update the referenced value, like in dotnetperls http://www.dotnetperls.com/ref .

  • But the functionality of `ref` is still identical irregardless of value or reference type. Either way, the original variable is not changed without `ref`. – Sami Kuhmonen Mar 28 '14 at 10:52
  • So with types that are passed be reference (e.g. class) I have always access to the newest version while for types that are passed by value (e.g. float) I have only the version of the moment it was passed to my class. I only need ref for those situations: change the origin of the passed value (primitive and non-primitive) or to have access to the updated origin primitive value. Did I understand this right? –  Mar 28 '14 at 11:08

6 Answers6

1

That is not what ref is for, the same behavior is achieved without it.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
1

You don't need the ref keyword here. Even without it, ClassB will hold a reference to ClassA, rather than a copy of its values.

Note that your code won't work because variableA is private, so ClassB can't access it in its Print method. Other than that, though, the output would be as you expected in your example

Ben Aaronson
  • 6,955
  • 2
  • 23
  • 38
1

ref has nothing to do with persistence. It only means that you can change the value of the original variable. If you call a method without ref, the method can assign that variable whatever they want and the caller's variable doesn't change. With ref, the caller will also point to another place.

Simple example:

void Call(int x)
{
  x = 2;
}

void CallRef(ref int x)
{
  x = 10;
}

int a=0;
Call(a); // a is still 0
CallRef(ref a); // a is 10
Sami Kuhmonen
  • 30,146
  • 9
  • 61
  • 74
1

Yes it does. But it is not even needed since objects are always pointers and the ref keyword is used to pass the pointer of non objects to functions (e.g: int, float, structs, etc.)

HellGate
  • 708
  • 1
  • 5
  • 20
0

Yes, it has the reference to it. It means that it does not save the values of the elements of ClassA but rather just its address in the memory (on the heap).

Therefore, make sure you do not reinstantiate classA:

classA.change(50) will work but classA = new ClassA() will not.

Also, please note that reference types (such as classes) do not need the ref keyword, they are automatically handled that way.

nxu
  • 2,202
  • 1
  • 22
  • 34
  • This is totally untrue. The function will always get a pointer to the object since it's a ref type. The elements are not copied with or without ref. Also `classA = new ClassA()` will work just fine. It just doesn't change the caller's variable to point to the new variable. And yes, reference types NEED `ref` if you actually want to do what `ref` is meant for. – Sami Kuhmonen Mar 28 '14 at 10:49
  • Nope. Reference types DO NOT need `ref` since they are always passed to variables as pointers (Just like you stated it in your second sentence). `Ref` is meant to be used with value types like int. Obviously, the instruction `classA = new ClassA()` works fine but what I meant was that classB will not have a reference to the newly instantiated object anymore, it will still have the reference to the old one. – nxu Mar 28 '14 at 12:43
  • Please explain how reference types don't need `ref` if I want to change the caller's variable to point somewhere else? That is exactly when you need `ref` with reference types, as well as with value types. – Sami Kuhmonen Mar 28 '14 at 12:48
  • Say you have `Method1` and `Method2`. `Method1` creates an object. `Method2` takes an object as a parameter, say '`object input`' and assigns to it a new one, e.g. '`input = new object()`'. If `Method1` calls `Method2`, after the call it will still hold the reference to the old object, not the one created inside `Method2`. But change the input parameter to be a `ref` parameter and now it works the other way, `Method1` will end up with a reference to the new object. – Ben Aaronson Mar 28 '14 at 12:54
  • http://puu.sh/7MFYG/6a3b2c7c8f.png - There is no need for the `ref` keyword. If this is not what you mean, it's my bad, I might just not understand the question. – nxu Mar 28 '14 at 14:06
  • There's no need for the ref keyword in the example from the question, but the point is that ref does change the behaviour even for reference types – Ben Aaronson Mar 28 '14 at 18:04
0

If you want to have access to the last instance of ClassA you can wrap your variable with a class like this:

public class Ref<T>
{
    readonly Func<T> getter;
    readonly Action<T> setter;

    public T Value
    {
        get
        {
            return getter();
        }
        set
        {
            setter(value);
        }
    }

    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
}

Then modify your ClassB like this:

public class ClassB
{
    readonly Ref<ClassA> refClassA;

    public ClassA ClassA
    {
        get
        {
            return refClassA.Value;
        }
    }

    public ClassB(Ref<ClassA> refClassA)
    {
        this.refClassA = refClassA;
    }

    public void Print()
    {
        Console.WriteLine(ClassA.VariableA);
    }
}

Then you can test and see if you have the behavior desired:

var a = new ClassA(1);
var b = new ClassB2(new Ref<ClassA>(() => a, x => a = x));

b.Print(); // output 1

var c = a; // backup old reference

a = new ClassA(2);

b.Print(); // output 2

// b stores old instance of a?
Console.WriteLine(object.ReferenceEquals(b.ClassA, c)); // output false
// a stores new instance of a?
Console.WriteLine(object.ReferenceEquals(b.ClassA, a)); // output true

I assume you wnat something like this, keep in mind that is a draft, so you have to work a lot.

EDIT

I had stolen the Ref<T> class from an blog of Eric Lippert, finally i found this SO question where he posted it.

Community
  • 1
  • 1
Alessandro D'Andria
  • 8,663
  • 2
  • 36
  • 32