3

我做需要连续数据的事情。现在有了 C# 10,我们可以做public readonly record struct.

我喜欢拥有记录所具有的自动 ToString 功能等,因此为我完成这项工作非常好。

因此,以下等效项吗?

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVector
{
    public readonly float X;
    public readonly float Y;
    public readonly float Z;

    public MyVector(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

与简洁的 C# 10 版本相比

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly record struct MyVectorRecord(float X, float Y, float Z)
{
}

或者有没有我会不小心踩到的地雷?我的意思是有什么事情是在幕后做的,record这使得我上面写的东西在连续包装方面不符合我的要求吗?我不能让记录插入填充、间距或做任何奇怪的事情。

我没有使用带有记录结构的向量类,而是出于说明目的使用它。您可以忽略诸如“浮点相等比较”之类的事情,因为我只对是否可以将其传递给期望 X/Y/Z 的连续序列的库感兴趣。

4

1 回答 1

3

record不是一种新类型,它是应用于引用类型和现在的值类型的特定行为。该结构仍然是一个结构。您可以在sharplab.io上对此进行测试,以查看编译器在每种情况下生成的代码。

但是,记录使用属性,而不是原始字段,因此您只能将结构与属性进行比较以记录结构。这是重要的区别

这个结构:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVectorRecord2
{ 
    public float X {get;} 
    public float Y {get;} 
    public float Z {get;}
    
     public MyVectorRecord2(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

生产

[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVectorRecord2
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <X>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <Y>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <Z>k__BackingField;

    public float X
    {
        [CompilerGenerated]
        get
        {
            return <X>k__BackingField;
        }
    }

    public float Y
    {
        [CompilerGenerated]
        get
        {
            return <Y>k__BackingField;
        }
    }

    public float Z
    {
        [CompilerGenerated]
        get
        {
            return <Z>k__BackingField;
        }
    }

    public MyVectorRecord2(float x, float y, float z)
    {
        <X>k__BackingField = x;
        <Y>k__BackingField = y;
        <Z>k__BackingField = z;
    }
}

虽然记录

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly record struct MyVectorRecord(float X, float Y, float Z)
{
}

产生:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVectorRecord : IEquatable<MyVectorRecord>
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <X>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <Y>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly float <Z>k__BackingField;

    public float X
    {
        [CompilerGenerated]
        get
        {
            return <X>k__BackingField;
        }
        [CompilerGenerated]
        init
        {
            <X>k__BackingField = value;
        }
    }

    public float Y
    {
        [CompilerGenerated]
        get
        {
            return <Y>k__BackingField;
        }
        [CompilerGenerated]
        init
        {
            <Y>k__BackingField = value;
        }
    }

    public float Z
    {
        [CompilerGenerated]
        get
        {
            return <Z>k__BackingField;
        }
        [CompilerGenerated]
        init
        {
            <Z>k__BackingField = value;
        }
    }

    public MyVectorRecord(float X, float Y, float Z)
    {
        <X>k__BackingField = X;
        <Y>k__BackingField = Y;
        <Z>k__BackingField = Z;
    }

    public override string ToString()
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append("MyVectorRecord");
        stringBuilder.Append(" { ");
        if (PrintMembers(stringBuilder))
        {
            stringBuilder.Append(' ');
        }
        stringBuilder.Append('}');
        return stringBuilder.ToString();
    }

    private bool PrintMembers(StringBuilder builder)
    {
        builder.Append("X = ");
        builder.Append(X.ToString());
        builder.Append(", Y = ");
        builder.Append(Y.ToString());
        builder.Append(", Z = ");
        builder.Append(Z.ToString());
        return true;
    }

    public static bool operator !=(MyVectorRecord left, MyVectorRecord right)
    {
        return !(left == right);
    }

    public static bool operator ==(MyVectorRecord left, MyVectorRecord right)
    {
        return left.Equals(right);
    }

    public override int GetHashCode()
    {
        return (EqualityComparer<float>.Default.GetHashCode(<X>k__BackingField) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(<Y>k__BackingField)) * -1521134295 + EqualityComparer<float>.Default.GetHashCode(<Z>k__BackingField);
    }

    public override bool Equals(object obj)
    {
        return obj is MyVectorRecord && Equals((MyVectorRecord)obj);
    }

    public bool Equals(MyVectorRecord other)
    {
        return EqualityComparer<float>.Default.Equals(<X>k__BackingField, other.<X>k__BackingField) && EqualityComparer<float>.Default.Equals(<Y>k__BackingField, other.<Y>k__BackingField) && EqualityComparer<float>.Default.Equals(<Z>k__BackingField, other.<Z>k__BackingField);
    }

    public void Deconstruct(out float X, out float Y, out float Z)
    {
        X = this.X;
        Y = this.Y;
        Z = this.Z;
    }
}

最后,这

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVector
{
    public readonly float X;
    public readonly float Y;
    public readonly float Z;

    public MyVector(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

保持不变,除了IsReadOnly属性。

[StructLayout(LayoutKind.Sequential, Pack = 4)]
[IsReadOnly]
public struct MyVector
{
    public readonly float X;

    public readonly float Y;

    public readonly float Z;

    public MyVector(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

最大的区别在于具有字段的结构和具有公共属性的结构。之后,record struct与具有属性的结构相比,a 仅包含额外的方法。

于 2021-10-19T06:30:24.577 回答