字段 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 中的任何方法中使用的字段值。
我的理解是:
- 您可以创建一个字段(例如
private int speed
)
- 创建一个 属性 以修改其值(
public int Speed {get;set;}
或 public int Speed {get => speed ; set => speed = value;}
但是编辑器(那里没有修改变量,它是硬代码)并没有抛出预期的结果,而是修改了 speed
字段值。
清晰简洁的解释表示赞赏。
在您的代码中,fireRate
和 FireRate
是完全独立的 field/property 以及 speed
和 Speed
。修改 fireRate
不会影响 FireRate
,反之亦然。
SerializeField
用于序列化字段而不是属性。在这两种情况下,只有字段(fireRate
和 speed
)被序列化。
试试下面的代码:
[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
- speed
和 FireRate
- 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
。
我有这段代码,我的 objective 是修改要在摘要 class 中的任何方法中使用的字段值。 我的理解是:
- 您可以创建一个字段(例如
private int speed
) - 创建一个 属性 以修改其值(
public int Speed {get;set;}
或public int Speed {get => speed ; set => speed = value;}
但是编辑器(那里没有修改变量,它是硬代码)并没有抛出预期的结果,而是修改了 speed
字段值。
清晰简洁的解释表示赞赏。
在您的代码中,fireRate
和 FireRate
是完全独立的 field/property 以及 speed
和 Speed
。修改 fireRate
不会影响 FireRate
,反之亦然。
SerializeField
用于序列化字段而不是属性。在这两种情况下,只有字段(fireRate
和 speed
)被序列化。
试试下面的代码:
[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
- speed
和 FireRate
- 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
。