Properties of Unity3D classes

Hello, Unity and C# experts. There is the thing that bothers me alot: I can not understand what property of Unity3D class returns:

  1. Pointer?

  2. Reference?

  3. Copy?

  4. Const pointer?

Let me explain:

f.e. if I access SpriteRenderer.sprite property then I’m not sure if I should check for sprite == null? And there is more confusion with sprite that I get - what is this? Copy? Could I change sprite properties and would it affect the original sprite that is contained in SpriteRenderer?

var sprite = myspriteRenderer.sprite; // what is sprite? pointer? reference? copy? could it be null?
if(sprite) // is this check necessary and why? how could I be sure about that?
{
    sprite.hideFlags = HideFlags.HideAndDontSave; // is the sprite in spriteRenderer affected by this?
    spriteRenderer.sprite = sprite; // is this necessary then?
}


// is this any different from code above?
mygameobject.GetComponent&ltSpriteRenderer&gt().sprite.hideFlags = HideFlags.HideAndDontSave;


// and then...
// is this different in any sort from property access? Does GetComponent() return real pointer to the object inside GameObject?
// would it modify the SpriteRenderer object inside GameObject?
mygameobject.GetComponent&ltSpriteRenderer&gt().sprite = Sprite::Create(...);

This is only one example but I would like to understand the whole concept of properties in Unity3D. Is there (maybe?) any docs that explain what are the return types of properties of each class? Or is there a rule, that states f.e.: “you can not modify Unity3D objects through the property directly (use local copy and assignment); all properties of Unity3D classes can not return null” or something?

It seems you are coming from a C/C++ background.

In C#, there are no more pointers (in fact, yes, there are, but their use are very limited).

In your case, a Sprite is a class, the sprite property of the SpriteRenderer class returns the reference to the sprite handled by the SpriteRenderer. Modifying the attributes of the sprite will modify the sprite handled by the SpriteRenderer.

The “only exception” I can think about is the materials property of a Renderer for instance. It returns a copy of the original array, but containing the “real” references to the materials. If you want to change one of the materials, you have to store the copy of the materials into a variable, manipulate this variable and use the setter to assign the new array.

Note that like all arrays returned by Unity, this returns a copy of materials array. If you want to change some materials in it, get the value, change an entry and set materials back.

Material[] materials = GetComponent<Renderer>().materials;
materials[0] = myMaterial;
GetComponent<Renderer>().materials = materials;

When structs are involved, the getter returns a copy of the variable, which explains the warning you get when you try do the following: transform.position.x = 10;. In this example, you are modifying the x attribute of the copy of the position.

Yes, checking for null is highly advised since your SpriteRenderer may not have a sprite assigned (meaning the getter will return null).

In the examples you have provided, you don’t need to call the setter of the sprite to “apply” the modifications to your sprite.

 var sprite = mygameobject.GetComponent<SpriteRenderer>().sprite;
 if(sprite)
 {
     // You are modifying the sprite handled by the SpriteRenderer
     sprite.hideFlags = HideFlags.HideAndDontSave;

     // Not needed
     //spriteRenderer.sprite = sprite;
 }

When you check the documentation of the SpriteRenderer class you will find the sprite property. As you can see it returns a Sprite. If you want to know about that return type, just klick on it.

At the top you see this line:

Sprite

  class in UnityEngine / Inherits from:Object / Implemented in:UnityEngine.CoreModule
    |          |                         |                               |
Yes, it's      |                 derived from the                        |
a class        |                UnityEngine.Object                       |
         defined in the                class                      located in the 
      UnityEngine namespace                                   UnityEngine.CoreModule.dll

Classes are reference types. In pure managed code you don’t have pointers, however managed references are similar to pointers but tracked by the GC. You also can’t do pointer arithmetic for security reasons.

To answer your questions one by one:

var sprite = myspriteRenderer.sprite;

This returns a reference of the class type Sprite

if(sprite) 

Yes, this might be necessary depending on what you want to do with the sprite. If it’s actually a null value and you try to access something from the Sprite class you obviously would get a NullReferenceException. However if you’re just passing the reference around without trying to dereference it, you don’t need to check if it’s null. The reason why your if statement works for UnityEngine.Object derived types is because UnityEngine.Object has implemented a conversion operator into bool which can be seen here

Note that if(obj) does not generally work in C#. To actually check if an arbitrary object is null or not you have to compare it to null if (obj != null).

sprite.hideFlags = HideFlags.HideAndDontSave;

Yes, this does affect the sprite that is referenced by this variable sprite. Note that when you reference an asset in your project, you shouldn’t mess with the hideflags. The hideflags are almost only relevant for editor functionality that isn’t part of your game.

 spriteRenderer.sprite = sprite;

The question if this is necessary is a bit confusing. What is necessary or not depends on what you want to do ^^. In your example code you’re reading the sprite reference from myspriteRenderer and you set the same Sprite for the spriteRenderer. If that’s what you’re intended to do, then yes, it is necessary ^^.

Finally some notes about GetComponent and references in general. GetComponent does also return a reference since everything that GetComponent can return has to be derived from Component. Since Component (and UnityEngine.Object) are classes, they are reference types.

From the managed code point of view, yes, GetComponent returns a direct reference to the component on that gameobject. Though behind the scenes it’s a bit more complicated. Unity is mainly written in C++. So the core is actually native code and not managed .NET / Mono. However we only directly work with managed classes in C#. The managed object for a component / gameobject / … are mostly just wrapper classes.

Unity has released the source code for the managed layer with a reference only license. So keep that in mind that you are not allowed to copy or use parts of that source code. It’s just there for reference. As you can see most things in the GameObject class are actually declared “external”. So when calling such a method / reading or writing a external property you actually execute a native method in the C++ core. Though this shouldn’t really matter in 99% of all cases.

Finally note that in C# and managed code it’s actually not possible to actively destroy an object. The destruction of objects is generally handled by the garbage collector. However since many classes (all objects derived from UnityEngine.Object) have a native code counterpart, they have to be destroyable. We actually have the Destroy method to destroy such objects. Though only the native part will be destroyed. The managed wrapper is still there until you loose all references to it and it is garbage collected. Note that destroyed objects are internally marked as destroyed and will turn into “Fake null objects”. If you want to know more about this, read this Unity blog post