【问题标题】:Field vs { get;set } vs { get=>field; set=>field = value;} - C# Unity字段 vs { get;set } vs { get=>field; set=>field = value;} - C# Unity
【发布时间】:2021-05-11 01:45:38
【问题描述】:

我有这段代码,我的目标是修改要在抽象类中的任何方法中使用的字段值。 我的理解是:

  • 您可以创建一个字段(例如private int speed
  • 创建属性以修改其值(public int Speed {get;set;}public int Speed {get => speed ; set => speed = value;}

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

【问题讨论】:

    标签: c# unity3d properties field


    【解决方案1】:

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

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

    试试下面的代码:

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

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

    【讨论】:

    • 不是回答者,但如果它解决了您的问题,请确保在 upvote/downvote 部分下方接受已回答的问题(小复选标记)。
    • 知道了ken。仍在等待有关“自动实现的属性有什么用”的答案
    • @HernandoN 财产的有用性是一个全新的讨论领域,所以我将留下链接:stackoverflow.com/questions/9304/…
    • @HernandoN 用简单的语言回答你的问题:Unity 劫持了 C#,这是一种不是为它设计的语言,甚至没有被引擎正确使用。在您不使用 Unity 的情况下,自动属性很有意义。
    【解决方案2】:

    您混淆了"field""property" 这两个术语。属性可以在 getter 和 setter 中实现额外的行为。

    首先:Unity 做not serialize properties!

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

    所以大部分时间都会想要像这样的模式

    [SerializeField] private int a;
    public int A => a;
    

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

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

    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;}
    

    这只允许这个类写,但其他人读这个值

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


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

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

    [SerializeField] private int _example;
    

    将显示为Example

    你很可能会选择

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

    【讨论】:

      【解决方案3】:

      [SerializeField] 标记字段

      属性是获取/设置值的方法的语法糖。

      当您声明像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

      【讨论】:

        猜你喜欢
        • 2018-04-08
        • 1970-01-01
        • 2020-01-24
        • 1970-01-01
        • 2022-12-02
        • 2019-08-30
        • 2021-04-20
        • 1970-01-01
        • 2011-01-21
        相关资源
        最近更新 更多