I have two struct instances that have a reference-type variable. I want to swap those two variables, but my first guess on how to do this looks like it doesn't work. My code looks something like this:
struct Foo
{
Bar m_bar;
}
void Main()
{
Foo a = new Foo();
Foo b = new Foo();
//swapping the values of m_bar of a and b
Bar temp = a.m_bar;
a.m_bar = b.m_bar;
b.m_bar = temp;
}
From what I could gather, it looks like since the variables are reference types, assigning b.m_bar to a.m_bar also assigns it to temp, messing up the swap.
So is my code wrong? If yes, what's the right way to swap two reference-type variables? If not, I guess my code messes up somewhere else.
Thanks!
1 Answer 1
The code in the question works fine, as shown in the minimal repro below. The confusion here is almost certainly something to do with mutable value-types; structs with mutable fields are notorious for confusion. I strongly recommend treating Foo as immutable, explicitly making it a readonly struct if your compiler supports it - something like:
readonly struct Foo
{
public Bar Bar { get; }
public Foo(Bar bar) => Bar = bar;
// not shown: override ToString, GetHashCode and Equals
}
But: with something more like your original code:
static class P
{
static void Main()
{
Foo a = new Foo { m_bar = new Bar("abc") };
Foo b = new Foo { m_bar = new Bar("def") };
System.Console.WriteLine("Before");
System.Console.WriteLine($"a.m_bar: {a.m_bar}"); // abc
System.Console.WriteLine($"b.m_bar: {b.m_bar}"); // def
//swapping the values of m_bar of a and b
Bar temp = a.m_bar;
a.m_bar = b.m_bar;
b.m_bar = temp;
System.Console.WriteLine("After");
System.Console.WriteLine($"a.m_bar: {a.m_bar}"); // def
System.Console.WriteLine($"b.m_bar: {b.m_bar}"); // abc
}
struct Foo
{ // note: public fields are usually a bad idea in any type
// note: mutable fields on value-types are usually a bad idea
public Bar m_bar;
}
class Bar
{
public string Name { get; }
public override string ToString() => Name;
public Bar(string name) => Name = name;
}
}
tempis an isolated snapshot of the reference as it was at the time you stored it (there is a way to do what you describe, but it requires special syntax - in particular "ref locals" - my point being: the code as shown should work fine)m_bar.