Search code examples
c#structref

Does accessing a field on a struct returned by ref copy the struct?


Given the method

ref readonly State GetState();

where State is a struct, the following code accesses State.SimTime without copying State:

ref readonly var state = ref GetState();
var t = state.SimTime;

Meanwhile this code does copy State:

var start = GetState();
var t =  state.SimTime;

My question is whether the following copies State:

var t = GetState().SimTime;

My hope is that it doesn't, since the result of GetState() is a ref and never assigned, but I don't know for sure and don't know how I would test for it.

As a bonus, is there a way to inspect code staticcally to determine whether memory is copied?


Solution

  • GetState().SimTime does not create a copy of State. You can see this by looking at the generated IL on SharpLab or some other tool.

    GetState().SimTime gets compiled to two call instructions:

    // IL pseudocode
    call GetState
    call get_SimTime
    

    The code snippet that uses a ref readonly var compiles to the same two call instructions.

    On the other hand, the code snippet that does not use ref readonly var compiles to:

    // IL pseudocode
    call GetState
    ldobj State
    stloc.0
    ldloca.s 0
    call get_SimTime
    

    The key instruction here is ldobj - this is what turns the reference that GetState returns, into an actual struct value (i.e. the copy of State). If you don't see an instruction like ldobj after calling a ref-return method, that means the code is operating on the reference returned by the method, and not a struct value.


    As Marc Gravell's answer says, the runtime would create a defensive copy if the getter of SimTime has side effects.