声明 属性 的最佳方式是什么

what the best way to declare a property

我正在从 Objective-C 切换到 C# 以开始使用 Unity 引擎。所以我试图吸收所有 C# 差异。 Obj-C 具有自动创建 getter 和 setter 的 @synthesize。老实说,它们对我来说有点陌生。在 Obj-C 中我经常这样做:

@synthesize myProperty = _myProperty;

然后在本地 class 代码中使用 _myProperty 并使用 myProperty 访问此 class 之外的 属性。或者更准确地说 classInstance.myProperty.

此外,在 Obj-C 中,您可以将 属性 声明为 readonly,而不必担心意外更改它在 class.

之外的值

在 C# 中,我试图编写适当的面向对象的代码,但我为此苦苦挣扎。我本质上是一名 C 编码员,并且很乐意随处访问所有内容,我知道这是不好的和不必要的。我也不想向 GameObject Inspector 公开大量属性。我更喜欢尽可能多地以编程方式进行。

那么声明属性的最佳方式是什么,这样我就可以从另一个 class 访问它们,而且它们不会暴露在 Inspector 中?以下是我遇到和使用过的一些可能性:

// 1. public static - public without being exposed in inspector
public static int myProperty;

// 2. the public _text doesn't appear in the inspector but the text one does.
public string _text;
public string text {
    get { return _text; }
    set {
        _text = value;
    }
}

// 3. private _underscore version with no setter - does removing the set make it read only?
private float _current;
public float current {
    get { return _current; }
}

// 4. creating my own getter function
private int myValue;
...
int GetMyValue() {
    return myValue;
}

另外.. 我在某处读到,在 .NET 中你不应该在 属性 名称中使用下划线。我真的不知道 属性 的下划线版本是做什么的或代表什么。我认为在 Obj-C 中它会影响范围,但我真的不知道。

我在调用变量属性时是否正确?

有人建议生成这个的 prop tab tab:

public object MyProperty {
            get;
            set;
}

不幸的是,这并没有真正回答我关于只读的问题。 int 或 string 甚至是对象吗?它不在 Obj-C 中。

创建属性的正确方法实际上取决于您要实现的目标。如果您只想创建一个 属性 以供进一步使用,您可以创建 shorthand 方式:

public object MyProperty { get; set; }

如果需要更多功能,您可以添加额外的功能,例如:

private int _myInt;

public int MyInt {
    get { return this._name; }
    set { 
        if (this._name == 1) {
            this._name = value;
        } else {
                this._name = 0;
        }
    }
}

您问题的答案完全取决于您希望实现的目标,两种方式都可以接受。

getter 和 setter 方法的使用,例如 Java 中的方法,在 C# 中是不受欢迎的。

为了回答你的另一个问题,String 是 C# 中的一个对象。 int 是原始类型。

这里是您遇到的问题的简要总结。

在 C# 中有一个所谓的 snippet 可以让您快速生成代码。它的快捷方式是输入 prop,然后按 Tab 键,这会生成类似这样的代码。

public int MyProperty { get; set; }

现在,如果您要创建字段,并且不想将其公开给实例。你应该做到 private.

例子

private int myVar; // private is not exposed on instances only public properties are
public int MyProperty
{
    get { return myVar; }
    set { myVar = value; }
}

现在对于 static 字段,static fields/properties 是类型可访问的。所以要隐藏它们,你只需要让它们 private

例子

private static bool myProp; // can't be accessed on the Program Type

public static bool MyProp { get; set; } // can be accessed on the Program Type

class MyClass
{
    public MyClass()
    {
        Program.MyProp = true;
        Program.myProp= true; // wont build
    }
}

如果你想让它只读并且防止修改,你可以这样做。

public int MyProperty { get; private set; } // can get but not set

private int myVar; 
public int MyProperty
{
    get { return myVar; } // same as the top but with a field
}

为了更深入、更好地理解,请阅读 What are Access Modifiers in C#?

NonSerialized 和 HideInspector 属性是您必须考虑从 Unity 检查器隐藏 class 成员的两个选项。 NonSerialized 不是 Unity 特有的,HideInspector 是 Unity 特有的。 Unity 在编译后的代码中查找这两个属性以确定在检查器中公开的内容。

如果你想要一个 publicly 只读 属性 你可以这样声明它...

[System.NonSerialized]
private string _text;

/// <summary>
/// Gets the Text
/// </summary>
/// <remarks>May be set within this class or derived classes</remarks>
public string Text {
    get { return _text; }
    protected set {
        _text = value;
    }
}

您似乎对访问修饰符的含义有疑问...

查看此页面...

https://msdn.microsoft.com/en-us/library/wxh6fsc7.aspx

简要...

  • public = 可从任何地方访问,不要将属性的支持变量声明为 public,否则人们可以简单地跳过您的 属性 访问器。
  • protected = 在您的 class 和继承 class
  • 的 classes 中可访问
  • 内部 = 在同一程序集中可访问
  • protected internal = 在同一个程序集中可访问 classes 继承了 class
  • 私有 = 只能在您的 class
  • 内访问

您只需声明

即可取消支持变量
/// <summary>
/// Gets or sets the Text
/// </summary>
public string Text { get; set; }

/// <summary>
/// Gets the current
/// </summary>
public float Current { get; protected set; }

auto-implemented variables 出现以来,没有任何技术原因需要使用支持变量创建属性,除非您有额外的逻辑希望在 get and/or 集上执行。

例如,您想要创建在 属性 更改时引发事件的 Observable 实体...

    private int _id;

    public int ID
    {
        get
        {
            return _id;
        }
        set
        {
            if (_id != value)
            {
                OnIDChanging(value);
                ReportPropertyChanging("ID");
                _id = StructuralObject.SetValidValue(value);
                ReportPropertyChanged("ID");
                OnIDChanged();
            }
        }
    }

关于编码标准,网上有很多。我会推荐 IDesign 的...

http://www.idesign.net/downloads/getdownload/1985

您会注意到我更改了您发布的代码的大小写,我使用的大小写符合 IDesign 的命名准则

Public 变量(不是字段)显示在 Unity 检查器中。如果你想隐藏一个public变量,你可以在它前面加上NonSerialized,像这样:

[System.NonSerialized]
public bool m_HideWhenInactive = false;

您也可以通过将其设为 属性 来完全避免此问题。检查器中未显示任何属性:

public bool m_HideWhenInactive { get; set; }

作为一个有趣的奖励(我知道这不是你的问题),你可以有一个 属性 世界阅读,私人写的:

public bool m_HideWhenInactive { get; private set; }

最后,如果您确实希望将变量序列化并存储在预制件中,但又不想让设计师对其进行编辑(如果您打算编写自定义编辑器 class),那么一个不同的注释:

[HideInInspector]
public bool m_HideWhenInactive = false;

检查器中永远不会显示静态字段。

Unity 引擎上下文中的

属性 模式往往与 C# 的 'norm' 略有不同,因为您通常对在编辑器中制作可调整数据感兴趣。这意味着序列化。

  • Unity 无法序列化属性
  • Unity 可以序列化原始类型的字段和继承自 UnityEngine.Object 的类型是序列化引用
  • Unity也可以序列化上述类型的列表和数组
  • MonoBehaviours 上的序列化字段在编辑器中公开并且可以编辑
  • public 字段默认序列化,如果用 [SerializeField] 属性标记则为私有字段。
  • 如果 class 是 MonoBehavior
  • 上的字段,Unity 也会序列化 class 上标有 [System.Serializable] 的字段

有关更深入的讨论,请参阅:https://blogs.unity3d.com/2014/06/24/serialization-in-unity/

以下模式是通用的,backing field 可以由开发者设置,不需要重新编译,并且在运行-time 不能被外部代码更改。

[SerializeField]
private int editableInEditor;

public int NotEditableInEditor
{
     get { return editableInEditor; }
}

这个模式也是,懒惰-getter。

private DerivedMonoBehaviour component;

public DerivedMonoBehaviour Component
{
     get 
     { 
         if(component == null)
         {
             // Note: Using the null-coalescing operator ??
             // is inadvisable when dealing with UnityEngine.Object
             // references.
             // See: https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/
             component = GetComponent<DerivedMonoBehaviour>();
         }
         return component;
     }
}