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.