在运行时如何在NET 5中检查C#9中的记录是不可变的

问题描述

记录是c#9 Net 5中的一项新功能

said

如果您希望整个对象都是不可变的,并且表现得像一个值,那么您应该考虑将其声明为记录

在NET 5的c#9中创建记录:

public record Rectangle
{
    public int Width { get; init; }
    public int Height { get; init; }
}

然后实例化它:

var rectangle = new Rectangle (20,30);

尝试更改值:

rectange.Width=50; //compiler error

编译器引发错误:

错误CS8852:只能在对象初始化程序中,或在实例构造函数或“ init”访问器的“ this”或“ base”上分配仅初始化属性或索引器“ Rectangle.Width”。

那是正确的,并确保记录是不变的。

使用方法like测试IsImmutable类型是否为false,因为在记录中没有生成的只读属性。

如何检查c#9中的记录,Net 5在运行时是不可变的,甚至具有init property

解决方法

记录在运行时确实是可变的。这是有意的,因为这意味着大多数序列化程序框架无需更新即可工作。

不过,可以通过检查以下内容来检查属性是否仅为initit:

public static bool IsInitOnly(PropertyInfo propertyInfo)
{
    return propertyInfo?.SetMethod.ReturnParameter
        .GetRequiredCustomModifiers()
        .Any(x => x.FullName == _isExternalInitName)
        ?? false;
}

private static string _isExternalInitName =
    typeof(System.Runtime.CompilerServices.IsExternalInit).FullName;
,

我认为不可能在运行时检查不变性。

以下是一些生成的代码供您记录。您可以看到这两个属性都有一个公共设置器。

public class Rectangle : IEquatable<Rectangle>
{
    [CompilerGenerated]
    private readonly int <Width>k__BackingField;

    [CompilerGenerated]
    private readonly int <Height>k__BackingField;

    protected virtual Type EqualityContract
    {
        [CompilerGenerated]
        get
        {
            return typeof(Rectangle);
        }
    }

    public int Width
    {
        [CompilerGenerated]
        get
        {
            return <Width>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Width>k__BackingField = value;
        }
    }

    public int Height
    {
        [CompilerGenerated]
        get
        {
            return <Height>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Height>k__BackingField = value;
        }
    }

以下代码将编译并运行,不会出现错误。

            var rect = new Rectangle { Height = 1,Width = 2 };
            typeof(Rectangle).GetProperty("Height").SetValue(rect,5);
            Console.Write(rect.Height);
            //Prints 5

在运行时,init访问器只是一个常规的setter。只是在编译时才进行检查,以仅允许在对象初始化期间调用init访问器。

所以我看不到任何方法可以在运行时检查Rectangle是不可变的。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...