Reputation: 191
I'm working with a framework that passes objects between classes by value and I need to update the reference to one of those objects. I can change property values of the original object just fine but I can't seem to figure out how to change the reference to an entirely new object. In one of the latter classes I'm retrieving a rather complex object from an API, hence my desire to just update a reference rather than attempt a deep copy.
I've tried calling SwapPerson{One,Two,Three,Four}
in my code sample with no hint of success. The output is always:
Main.person: Groucho Marx is 128 years old!
Main.person: Groucho Marx is 129 years old!
Main.person: Groucho Marx is 129 years old!
I'm hoping there's a simple solution that I'm overlooking due to the late hour, so any input is greatly appreciated.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"{FirstName} {LastName} is {Age} years old!";
}
}
public class Foo
{
private Person person;
public Foo(Person person)
{
this.person = person;
}
public void SetAge(int age)
{
person.Age = age;
}
public void SwapPersonOne(Person newPerson)
{
person = newPerson;
}
public void SwapPersonTwo(ref Person newPerson)
{
person = newPerson;
}
public void SwapPersonThree(Person newPerson)
{
LocalSwap(ref person);
void LocalSwap(ref Person oldPerson)
{
oldPerson = newPerson;
}
}
public void SwapPersonFour(Person newPerson)
{
LocalSwap(ref person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person _newPerson)
{
oldPerson = _newPerson;
}
}
}
static void Main(string[] args)
{
Person person = new Person { FirstName = "Groucho", LastName = "Marx", Age = 128 };
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
var foo = new Foo(person);
foo.SetAge(129);
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
var charlie = new Person { FirstName = "Charlie", LastName = "Chaplin", Age = 130 };
//foo.SwapPersonOne(charlie);
//foo.SwapPersonTwo(ref charlie);
//foo.SwapPersonThree(charlie);
foo.SwapPersonFour(charlie);
Console.WriteLine($"{nameof(Main)}.{nameof(person)}: {person}");
Console.ReadLine();
}
Upvotes: 0
Views: 2142
Reputation: 29207
You're using the ref
keyword within the inner local function, but not in the outer function. Also, if the intention is actually to swap the references, the method doesn't do that as-is.
public void SwapPersonFour(Person newPerson)
{
LocalSwap(ref person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person _newPerson)
{
oldPerson = _newPerson;
}
}
oldPerson
and _newPerson
are passed to the local function by reference, but newPerson
is passed to SwapPersonFour
by value.
Also, only oldPerson
is updated, so now both oldPerson
and _newPerson
refer to the same Person
.
If you want to update the reference passed to SwapPersonFour
you must also pass that argument by reference using the ref
keyword.
public void SwapPersonFour(ref Person newPerson)
The comment mentioned that it didn't work, so I put together a hasty unit test to see if I was missing something. (I miss stuff all the time, which is why I write unit tests.)
[TestClass]
public class UnitTest1
{
private Person _person;
[TestMethod]
public void TestSwappingPerson()
{
_person = new Person { FirstName = "Scott" };
var newPerson = new Person() { FirstName = "Bob" };
SwapPersonFour(ref newPerson);
Assert.AreEqual("Bob", _person.FirstName);
}
public void SwapPersonFour(ref Person newPerson)
{
LocalSwap(ref _person, ref newPerson);
void LocalSwap(ref Person oldPerson, ref Person localNewPerson)
{
oldPerson = localNewPerson;
}
}
}
SwapPersonFour
replaces the _person
field with a reference to newPerson
. It's not actually swapping anything because while it's updating _person
it's not updating newPerson
. When it's done they are both references to the same Person
. (Did you mean to swap them? That could be the problem.)
For what it's worth, I would remove the local function because it doesn't actually do anything. It just takes the one thing that the method does and nests it in an extra function. You could replace it with this and get the same result - it's just easier to read. (In fact, the extra code might have made it easier to miss that nothing was getting swapped. I don't know about you, but it doesn't take much to confuse me.)
public void SwapPersonFour(ref Person newPerson)
{
_person = newPerson;
}
If you actually want to swap them then you could do this:
public void SwapPersonFour(ref Person newPerson)
{
var temp = _person;
_person = newPerson;
newPerson = temp;
}
Upvotes: 2