字段 vs { get;set } vs { get=>field; set=>field = value;} - C# Unity

Field vs { get;set } vs { get=>field; set=>field = value;} - C# Unity

我有这段代码,我的 objective 是修改要在摘要 class 中的任何方法中使用的字段值。 我的理解是:

但是编辑器(那里没有修改变量,它是硬代码)并没有抛出预期的结果,而是修改了 speed 字段值。 清晰简洁的解释表示赞赏。

在您的代码中,fireRateFireRate 是完全独立的 field/property 以及 speedSpeed。修改 fireRate 不会影响 FireRate,反之亦然。

SerializeField 用于序列化字段而不是属性。在这两种情况下,只有字段(fireRatespeed)被序列化。

试试下面的代码:

    [SerializeField] public int a;
    [SerializeField] public int b { get; set; }
    [SerializeField] public int c => a;

Unity默认不序列化属性,只会序列化a

您混淆了术语 "field" and "property"。属性可以在 getter 和 setter.

中实现额外的行为

首先:Unity not serialize properties!

这将 Unity 中属性的用途限制在运行时。

所以大多数时候会想要像

这样的模式
[SerializeField] private int a;
public int A => a;

这例如目的是您可以通过编辑器分配一个值,由 class 本身编辑它,但只允许其他人只读访问 => 封装。

当然,为了完整性,它可以执行额外的完整性检查,例如

private const int min = -3;
private const int max = 17;
private bool allowSet;

[SerializeField] private int a;
public int A 
{
    get => a;
    set 
    {
        if(allowSet) a = Mathf.Clamp(a, min, max);
    }
}

几乎不需要自动属性(在我看来)除了你想像

一样直接限制访问
public int b { get; private set;}

这只允许这个 class 写入但其他人都可以读取这个值

所以什么时候有用主要是主观的,取决于具体情况。


现在看你的代码,Speed - speedFireRate - fireRate 之间完全没有关系!它们是完全独立的字段和属性。

这里的混淆可能是由于 Inspector 创建的显示名称。它会自动使所有字段名称大写

[SerializeField] private int _example;

将显示为Example

你很可能会选择

[SerializeField] protected float Speed;
[SerializeField] protected float FireRate;

[SerializeField] 标记 字段 .

属性是方法的语法糖getting/setting一个值。

当你声明一个像public int Speed {get;}这样的属性时,编译器会生成一个隐藏的backing字段,它是值实际存储的地方,这个字段是私有的,因此不会被 Unity 的序列化器自动序列化。 (此外,编译器会生成一个方法 public int get_Speed(),它是 属性 的 get 实现 ,您可以通过自己声明此方法来验证这一点, 编译器应该抱怨已经存在具有相同签名的成员。)

C# 7.3 添加了 Auto-implemented property field-targeted attributes,允许您这样做:

[field:SerializeField] public int Speed {get;}

这会将 SerializeField 属性应用于隐藏的生成字段,Unity 应该会正常序列化它。请注意,如果您计划实施自定义检查器或 属性 抽屉,请记住此隐藏字段的名称将具有特殊名称 <Speed>k__BackingField