1

I'm switching from Objective-C to C# to start using the Unity engine. So I'm trying to soak in all the C# differences. Obj-C has the @synthesize that auto creates the getters and setters. To to be honest they're sort of new to me. In Obj-C I'd often do:

@synthesize myProperty = _myProperty;

Then use the _myProperty in the local class code and access that property outside of this class using myProperty. Or more accurately classInstance.myProperty.

Also in Obj-C you can declare a property to be readonly and not worry about accidentally changing it's value outside the class.

In C# I'm trying to write proper object oriented code and I struggle with this. I'm a C coder at heart and am comfortable having access to everything everywhere, which I know is bad and unnecessary. I also don't want to expose tons of properties to the GameObject Inspector. I prefer to do as much programmatically as possible.

So what is the best way to declare properties so I can access them from another class but also so they are not exposed in the Inspector? Here are some possibilities that I've encountered and used:

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

Also.. I read somewhere that in .NET you shouldn't use underscores in property names. I don't really know what the underscore version of the property does or represents. I thought in Obj-C it effected the scope, but don't really know.

Am I even correct in calling variables properties?

Someone suggested prop tab tab which produces this:

public object MyProperty {
            get;
            set;
}

Unfortunately that doesn't really answer my question about read only. Is an int or string even an object? It's not in Obj-C.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
badweasel
  • 2,349
  • 1
  • 19
  • 31
  • Type `prop` and push tab twice. Also, the convention in C# is to capitalize your properties. – Drew Kennedy Jan 30 '15 at 01:58
  • 1
    Is a string or an int an object? Cause they're not in Obj-c. And I'm hoping to get some answers about the _version of a property and if I should use them. I'll modify my question. – badweasel Jan 30 '15 at 02:03
  • 1
    string is an object, int is a primitive. However, in C# you have a keyword for string, or you can call the class directly, i.e. `string` or `String`. – Drew Kennedy Jan 30 '15 at 02:05

5 Answers5

2

Public variables (not fields) are shown in the Unity inspector. If you want a public variable to be hidden, you can preface it with NonSerialized, like this:

[System.NonSerialized]
public bool m_HideWhenInactive = false;

You can also avoid this problem entirely by making it a property. No properties are shown in the inspector:

public bool m_HideWhenInactive { get; set; }

As a fun bonus (not your question, I know), you can have a property that's world-read, private-write:

public bool m_HideWhenInactive { get; private set; }

And finally, if you DO want a variable to be serialized and stored in a prefab, but you don't want the designers editing it (if you intend to write a custom editor class), there's a different annotation for that:

[HideInInspector]
public bool m_HideWhenInactive = false;

Static fields are never shown in the inspector.

piojo
  • 6,351
  • 1
  • 26
  • 36
  • As a general rule public fields in a class like public bool m_HideWhenInactive are not advisable, leads to code sludge. Plus your naming standards are all over the shop. Look at the IDesign coding standard for C# I linked below. You're applying the same naming conventions for both member variables and properties, the two are distinctly different and should be named as such. – Mick Jan 30 '15 at 04:16
  • Despite all that I gave you the +1 for the [System.NonSerialized] and [HideInInspector] attributes, which is what he's really after – Mick Jan 30 '15 at 04:19
  • Thanks @Mick. In my project I actually use different naming conventions for variables versus properties. As far as public variables and spaghetti code, I prefer not to argue in the abstract about the specific. There is a time and a place for everything. – piojo Jan 30 '15 at 06:35
  • There's never a time or a place for public fields in any class I create that's part of any substantial system. See the top ranked answer for 3 very good reasons why you should always declare fields as private... http://stackoverflow.com/questions/1180860/public-fields-versus-automatic-properties – Mick Jan 30 '15 at 06:39
  • @Mick, thank you for taking the time to answer. Your link references this page, Jeff Atwood's blog, which disagrees: http://blog.codinghorror.com/properties-vs-public-variables/ . His main points are "Keep it Simple Stupid", and "Don't write code you don't need to write". Plus, I've found the three "use properties not variables" reasons to be inapplicable/inapplicable/usually inapplicable to game development in Unity. To sum it up, I agree with Atwood: use common sense, and try to write clear, short code. – piojo Jan 30 '15 at 08:16
  • This is an argument that could rage on and on, the upshot of it is, you go around declaring fields everywhere, one day it's going to bite you in the ass. In terms of added complexity between a field and an automatic property, i'd say there's almost none how complex is it to type { get; set; } ? To create a property with a backing variable it's private int _blah; followed by Crtl-R+E and you have a property. Here's one argument that applies to unity, try setting a breakpoint on a field to see when and what is changing it, you can't, with a property you can. – Mick Jan 30 '15 at 08:33
1

The NonSerialized and HideInspector attributes are the two options you must consider to hide members of the class from the Unity inspector. NonSerialized is not specific to Unity, HideInspector is specific to Unity. Unity looks for both of these attribute in your compiled code to determine what gets exposed in the inspector.

If you want a publicly read only property you declare it like so...

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

You seem to be having issues with the meaning of access modifiers...

See this page...

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

Briefly...

  • public = accessible from anywhere, do not declare backing variables on properties as public, otherwise people can simply skip your property accessor.
  • protected = accessible within your class and from classes inheriting the class
  • internal = accessible within the same assembly
  • protected internal = accessible within the same assembly and from classes inheriting the class
  • private = accessible only within your class

You can do away with backing variables simply by declaring

/// <summary>
/// Gets or sets the Text
/// </summary>
public string Text { get; set; }

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

Since the advent of auto-implemented variables, there are no technical reasons for creating properties with backing variables unless you have additional logic you would like executed on the get and/or set.

e.g you wanted to create Observable entities that raise an event when a property is changed...

    private int _id;

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

In terms of coding standards, there are plenty of them on the net. I'd recommend IDesign's...

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

You'll notice I changed the casing on the code you posted, the casing I've used adhere's to IDesign's naming guidelines

Mick
  • 6,527
  • 4
  • 52
  • 67
  • I'm going to have to play around a little and try to "get" this before picking an answer. Can I ask.. `_text=value` the keyword `value` is just automatically whatever is sent to the setter? And also below where you just say `set;` that just does it without having to put the code? – badweasel Jan 30 '15 at 05:41
  • Yes value is a keyword in C# and represents the data set by the code setting the property. https://msdn.microsoft.com/en-us/library/a1khb4f8.aspx I've added a bit of extra information about using backing variables versus auto-implemented properties (with no backing variables). – Mick Jan 30 '15 at 06:25
  • You might also be wondering what attributes like Unity's HideInInspector and the .NET NonSerialized are in C#. https://msdn.microsoft.com/en-us/library/system.nonserializedattribute%28v=vs.110%29.aspx Attributes are used simply to annotate the code, an engine like Unity or the .NET serializer can then use inspect the code dom and use this meta data about the code to change the behavior of the system processing your code. – Mick Jan 30 '15 at 06:33
  • There were several answers here that were probably correct. But this one helped me more overall. Thanks to everyone for answering though. – badweasel Jan 30 '15 at 07:54
0

The correct way to create properties really depends on what it is you're trying to accomplish. If you're only wanting to have a property be created for further use you can create the shorthand way:

public object MyProperty { get; set; }

If more functionality is required, you can add additional functionality, such as:

private int _myInt;

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

The answer of your question is it simply depends on what it is you're looking to achieve and both ways are accepted.

The use of getter and setter methods, such as those found in Java, are frowned upon in C#.

To answer your other question, String is an object in C#. int is a primitive type.

Drew Kennedy
  • 4,118
  • 4
  • 24
  • 34
0

Here's a quick summary of your problems.

There is a so called snippet in C# that allows you to quickly generate code. The quick shortcut for it is typing prop and then pressing tab which would generate a code to something like this.

public int MyProperty { get; set; }

Now if you're going to create fields, and you dont want to expose that to an instance. You should make it private.

Example

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

Now for static fields, static fields/properties are type accessible. So to hide them, you only have to make them private

Example

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

If you want it to be readonly and prevent modification, you can do it like this.

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
}

For a deeper and better understanding, please do read about What are Access Modifiers in C#?

DevEstacion
  • 1,947
  • 1
  • 14
  • 28
  • I'm sorry that I'm not explaining myself right. I want to expose it read only to other classes where I use an instance of the class. I don't want it to be completely public because I don't want a designer to edit the value in the unity game object inspector. I want a get but not a set. Are any of my examples wrong? Or would any of them work? – badweasel Jan 30 '15 at 03:25
0

Property patterns in the context of the Unity engine tend to differ slightly to the 'norm' of C# because of you are often interested in making them tweakable data in the editor. This means serialization.

  • Unity cannot serialize properties
  • Unity can serialize fields of primitive types and types inheriting from UnityEngine.Object are serialized references
  • Unity can serialize list and arrays of the types mentioned above as well
  • Serialized fields on MonoBehaviours are exposed in the editor and are editable
  • public fields are serialized by default and private fields if they are marked with the [SerializeField] attribute.
  • Unity also serializes fields on classes marked with [System.Serializable] if the class is a field on a MonoBehavior

For a more in-depth discussion see: https://blogs.unity3d.com/2014/06/24/serialization-in-unity/

The following pattern is common, the backing field can be set by the developer, without needing to recompile, and cannot be changed by external code at run-time.

[SerializeField]
private int editableInEditor;

public int NotEditableInEditor
{
     get { return editableInEditor; }
}

So is this pattern, a lazy-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;
     }
}