Home > Software engineering >  Are record structs passed by value or by reference and can they be blittable or not
Are record structs passed by value or by reference and can they be blittable or not

Time:02-03

Working with a very large number structs as well as Arrays and Lists of structs I'm always annoyed by the the usual hurdles to reduce the number of copies of said structs when passing them to methods or working with them in diverse ways.

In addition I am forced to use structs as I need to use blittable types.

I also know about things like ErrorProne.NET which helps a lot but I'm still not fine with the Solution I currently have.

Now, with the latest C# and .NET-Versions we have the record-type which can be applied to both, structs and classes or used standalone but I can't find any clear information regarding copy-when-passing beheaviour and similar stuff and about how a record struct behaves compared to a normal struct and whether record structs can be blittable or not.

Following an Example of the structs (here record structs) I'm talking about. In the optimal case, I would even like to use them in combination with a Custom ObjectPool allowing me to re-use them without my program having to allocate the memory for new of these structs again and again while GC-ing old unused ones.


[StructLayout(LayoutKind.Sequential)]
public record struct PagedSecondaryIndexKey
{
    [MarshalAs(UnmanagedType.U1)]
    public SecondaryIndexType IndexType;

    [MarshalAs(UnmanagedType.U8)]
    public ulong Page;
    
    [MarshalAs(UnmanagedType.Struct)]
    public IndexIdentifier IndexIdentifier;
    
    public PagedSecondaryIndexKey(ulong page, SecondaryIndexType indexType, ulong identifier1, ulong identifier2, ulong identifier3)
    {
        IndexType = indexType;
        Page = page;
        IndexIdentifier.Reset(identifier1, identifier2, identifier3);
    }

}

[StructLayout(LayoutKind.Sequential)]
public record struct IndexIdentifier
{
    [MarshalAs(UnmanagedType.U8)]
    private ulong IndexIdentifier1;

    [MarshalAs(UnmanagedType.U8)]
    private ulong IndexIdentifier2;
    
    [MarshalAs(UnmanagedType.U8)]
    private ulong IndexIdentifier3;
    
    public const int Size = 3 * sizeof(ulong);
    
    public IndexIdentifier(ulong identifier1, ulong identifier2, ulong identifier3)
    {
        IndexIdentifier1 = identifier1;
        IndexIdentifier2 = identifier2;
        IndexIdentifier3 = identifier3;
    }
    
    public IndexIdentifier(IndexIdentifier indexKeyIndexIdentifier)
    {
        indexKeyIndexIdentifier.IndexIdentifier1 = IndexIdentifier1;
        indexKeyIndexIdentifier.IndexIdentifier2 = IndexIdentifier2;
        indexKeyIndexIdentifier.IndexIdentifier3 = IndexIdentifier3;
    }

}

Tried diverse things to solve the Problems mentions, used diverse tools, did a lot of research but still havn't found the answer I'm looking for.

CodePudding user response:

Basically, records just add a number of default methods to the class (ToString, Equals, etc.) but otherwise a record class behaves like a class (it's a reference type) and record struct behaves like a struct (it's a value type).

That also means that a record struct is blittable if and only if an equivalent struct would be blittable. Which basically means that a struct/record struct must not contain references to be blittable.

  • Related