Why passing ref struct to methods actually passes a copy of a ref struct?

Advertisements

When I’m trying to pass a ref struct that looks like, say

public ref struct BufferWriter
{
    readonly Buffer* _pb;
    public int WrittenBytes;
    //...
    public bool Append(ReadOnlySpan<byte> buffer)
    {
        //...
        WrittenBytes += buffer.Length;
        //...
    }
    
}

to a method (Write100U8Chars(BufferWriter, Object) in the following example), a struct is not actually passed by a reference, but by the value:

protected override bool Serialize(object obj)
{
    //...
    fixed (Buffer* pb = &doc_body)
    {
        using (BufferWriter writer = new BufferWriter(pb))
        {
            writer.Append("UTF8 str"U8);
            // pb->Bytes is now 8
            // writer.WrittenBytes is now also 8
            Write100U8Chars(writer, obj);
            // pb->Bytes is now 108
            // But writer.WrittenBytes is still 8!
        }
    }
    //...
}

// A method that always calls BufferWriter.Append passing 100 UTF-8 chars (aka bytes) 
protected abstract bool Write100U8Chars(BufferWriter writer, object obj);

Because of the using block being kind of read-only context which, as I supposed, enforces making "defensive copies", I’ve attempted to remove the using block/directive:

fixed (Buffer* pb = &doc_body)
{
    BufferWriter writer = new BufferWriter(pb)
    writer.Append("UTF8 str"U8);
    // writer.WrittenBytes is now 8
    Write100U8Chars(writer, obj);
    // No use of removing using: writer.WrittenBytes is still 8
}

Making BufferWriter a ref readonly struct makes no difference.

Passing a writer local to a method Write100U8Chars(BufferWriter, Object) with in parameter still makes no difference.

How can I make a ref struct be passed into abstract method by reference and not by value like it is the case with ordinary non-ref structs?

>Solution :

protected abstract bool Write100U8Chars(BufferWriter writer, object obj);

This call is passing writer by value. If you want to pass it by reference, it should be:

protected abstract bool Write100U8Chars(ref BufferWriter writer, object obj);

As far as I understand it, the ref in the struct declaration is used to define how the value type can be allocated (only stack) but it will still behave as a regular struct and get passed by value by default.

Leave a ReplyCancel reply