Kornelije Petak
Kornelije Petak

Reputation: 9572

Save a object reference for future usage using ref keyword

Say I have a simple class like this:

public class ReferenceChanger<T> 
{
    public T SavedElement { get; private set; }

    public ReferenceChanger(T elementToSave)
    {
        SavedElement = elementToSave;
    }

    // This method would change the original variable (given as a constructor argument)
    public void SetNewReference(T newElement)
    {
        SavedElement = newElement;
    }
}

This class saves an element given to its constructor, whatever element is. However, the "SavedElement" (its backing field) is a reference to the object given at the time of instance creation.

Is there any way to save a reference to a variable (as with using ref keyword), so that if the original item passed to the constructor changes, the SavedElement would automatically reflect the change, almost as if the object was passed with the ref keyword? (Even if I use the ref keyword, I would not be able to save the reference that way.)

Updated to make intentions more clear:

public class ExampleClass 
{
    public List<int> Numbers { get; set; }
}

public static void Main()
{
    ExampleClass temp = new ExampleClass();
    temp.Numbers = new List<int>() { 1, 2, 3 }; 

    ReferenceChanger<List<int>> changer = new ReferenceChanger<List<int>>(temp.Numbers);
    // Here, a reference to the List<int> instance (containing 1,2,3) is stored in changer's SavedElement

    // Then I do this:
    changer.SetNewReference(new List<int>() { 5, 6, 7 });

    // Now, only changer's SavedElement was changed, but temp's property Numbers was not changed.
    // Is there a way to change the temp's property Numbers from the changer?
}

Upvotes: 3

Views: 5061

Answers (3)

Anthony Pegram
Anthony Pegram

Reputation: 126992

You cannot normally capture a reference to a variable and store it as a property. One hackish solution (not really suggesting it's a good idea, I'd explore other avenues first) is to capture it in a closure and pass the closure around. Closures capture variables, not values. As a result, changes to variables can be observed elsewhere. For example, given

class Foo
{
    public int Baz { get; set; }
}

class Bar
{
    private Func<Foo> fooGetter;

    public Bar(Func<Foo> fooGetter)
    {
        this.fooGetter = fooGetter;
    }

    public void Do()
    {
        Console.WriteLine(fooGetter().Baz);
    }
}

You can have

Foo foo = new Foo() { Baz = 1 };
Bar bar = new Bar(() => foo);
bar.Do();
foo = new Foo() { Baz = 2 };
bar.Do();

Changes to the variable foo are observed, since that is what the caller enclosed in the lambda. Had the caller simply said () => new Foo(), you would (of course) not observe any changes.

Upvotes: 0

Ben Voigt
Ben Voigt

Reputation: 283931

Sounds like you're looking for TypedReference and the __makeref keyword.

Warning: they're poorly documented and not in the standardized part of C#.

There's a lot more information in this question.

Upvotes: 4

Garrett Vlieger
Garrett Vlieger

Reputation: 9494

All classes in C# are reference objects so what you have coded should update the value of SavedElement. However, if T is a primitive type (e.g., int, string, etc.), this would not work since these are set by value. You would need to put a constraint on T to make sure it's a class.

Upvotes: 0

Related Questions