Update your C # in Unity ~ Expression-style function members ~

5 minute read

There was a time when only old C # could be used in Unity. But that’s a thing of the past. The latest LTS at the time of this writing, Unity 2019.4, supports C # 7.3. In addition, C # 8.0 will be supported in Unity 2020.2, the latest Beta version at the time of this writing.

Since I could only use old C # in Unity for a long time, I think there are many people who say “Is there such a function in C #? I didn’t know!”. In this “Update your C # in Unity” series, we will introduce “You can use relatively new features of C # in Unity like this!”.


Language feature name: expression-style function member
Added version: New addition in C # 6.0, possible addition of members in C # 7.0
Description: Ability to describe members more concisely if the implementation of a member, such as a method or property, is a single expression.


When writing code in C #, there are times when you write a method that just calls a single method. For example, a method that calls StartCoroutine and returns a Coroutine as follows:

using System.Collections;
using UnityEngine;

public class Launcher : MonoBehaviour
{
    public Coroutine Launch()
    {
        return StartCoroutine(LaunchImpl());
    }

    private IEnumerator LaunchImpl()
    {
        //Abbreviation
        yield break;
    }
}

When the method implementation is written in a single expression like this, the method can be written in a more concise expression format.

using System.Collections;
using UnityEngine;

public class Launcher : MonoBehaviour
{
    //Described in expression format
    //return or{Or}I don't need
    public Coroutine Launch() => StartCoroutine(LaunchImpl());

    private IEnumerator LaunchImpl()
    {
        //Abbreviation
        yield break;
    }
}

return, {,} are boilerplate descriptions that are not the essence of processing. By utilizing the function members in the form of expressions, it became a concise description that described only the essence of processing.

By the way, you can also write a method whose return value is void as follows.

using UnityEditor;

public static class AssetUpdater
{
    [MenuItem("Assets/ForceReserializeAssets")]
    private static void ForceReserializeAssets() => AssetDatabase.ForceReserializeAssets();
}

Expression-style function members are often used for simple processing implementations of ToString methods and getter-only properties.

[Serializable]
public class Circle
{
    [SerializeField]
    private float x;
    
    [SerializeField]
    private float y;

    [SerializeField]
    private float radius;
    
    public Circle(float x, float y, float radius)
    {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    //Can also be used to return a field as is
    public float X => x;
    public float Y => y;
    public float Radius => radius;

    //Can also be used for properties that describe logic
    public float Area => Mathf.PI * radius * radius; 

    //Can also be used to implement ToString
    public override string ToString() => $"Center ({X},{Y}) Radius:{Radius}";
}

It can also be used for properties and indexers that have both getters and setters.

[Serializable]
public class State
{
    [SerializeField] private int score;

    public State(int score)
    {
        this.score = score;
    }
        
    public int Score
    {
        get => score;
        set => score = value;
    }
}


public class Dungeon
{
    private int[][] map;

    public int this[int i, int j]
    {
        set => map[i][j] = value;
        get => map[i][j];
    }
}

You may be wondering, “Isn’t it happy to be shortened?”
The answer to that question is, “When a lot of short members are lined up, I’m glad that it becomes very short if I write it in the form of a formula.”
For example, if you implement some Vector2 operators in the traditional way, you’ll probably get this:

    public static Vector2 operator +(Vector2 a, Vector2 b) {
        return new Vector2(a.x + b.x, a.y + b.y);
    }

    public static Vector2 operator -(Vector2 a, Vector2 b) {
        return new Vector2(a.x - b.x, a.y - b.y);
    }

    public static Vector2 operator *(Vector2 a, Vector2 b) {
        return new Vector2(a.x * b.x, a.y * b.y);
    }

    public static Vector2 operator /(Vector2 a, Vector2 b) {
        return new Vector2(a.x / b.x, a.y / b.y);
    }

    public static Vector2 operator -(Vector2 a) {
        return new Vector2(-a.x, -a.y);
    }

    public static Vector2 operator *(Vector2 a, float d) {
        return new Vector2(a.x * d, a.y * d);
    }

    public static Vector2 operator *(float d, Vector2 a) {
        new Vector2(a.x * d, a.y * d);
    }

    public static Vector2 operator /(Vector2 a, float d) {
        return new Vector2(a.x / d, a.y / d);
    }

It takes up a lot of space with { and }.
It’s nice to describe members in a formula format when the members are lined up like this. The non-essential “ return, {, } “does not take up the number of lines or space.

This will be shorter like this.

    public static Vector2 operator +(Vector2 a, Vector2 b) => new Vector2(a.x + b.x, a.y + b.y);

    public static Vector2 operator -(Vector2 a, Vector2 b) => new Vector2(a.x - b.x, a.y - b.y);

    public static Vector2 operator *(Vector2 a, Vector2 b) => new Vector2(a.x * b.x, a.y * b.y);

    public static Vector2 operator /(Vector2 a, Vector2 b) => new Vector2(a.x / b.x, a.y / b.y);

    public static Vector2 operator -(Vector2 a) => new Vector2(-a.x, -a.y);

    public static Vector2 operator *(Vector2 a, float d) => new Vector2(a.x * d, a.y * d);

    public static Vector2 operator *(float d, Vector2 a) => new Vector2(a.x * d, a.y * d);

    public static Vector2 operator /(Vector2 a, float d) => new Vector2(a.x / d, a.y / d);

It became very short when I listed it.

By the way, it can also be used in the constructor. In combination with “read-only automatic properties” and “tuple generation / decomposition”, you can also apply something like this. (I use value tuples, but they don’t generate value tuples internally.) I sometimes see this writing in official Microsoft documentation.

public class Point {
    public int X { get; }
    public int Y { get; }
    
    public Point(int x, int y) => (X, Y) = (x, y);
}

//Internally it looks like this
//I'm using value tuples, but no value tuples are generated internally https://sharplab.io/#v2:EYLgtghgzgLgpgJwDQBMQGoA+ABATARgFgAoE7AZgAI9KAFAewEsA7GSgbxMu+qpbYAaHSgHM4MANyUAvlx4VK/SgE1hYyTLnctvOk1YAKJQA8ki1pQCeASkoBeAHyUDAs8tt3npq9YklZxEA===
//public class Point
//{
//    [CompilerGenerated]
//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
//    private readonly int <X>k__BackingField;
//
//    [CompilerGenerated]
//    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
//    private readonly int <Y>k__BackingField;
//
//    public int X
//    {
//        [CompilerGenerated]
//        get
//        {
//            return <X>k__BackingField;
//        }
//    }
//
//    public int Y
//    {
//        [CompilerGenerated]
//        get
//        {
//            return <Y>k__BackingField;
//        }
//    }
//
//    public Point(int x, int y)
//    {
//        <X>k__BackingField = x;
//        <Y>k__BackingField = y;
//    }
//}

Expression-style function members allow you to describe members more concisely if the implementation of a member, such as a method or property, is a single expression.
You may be wondering, “Isn’t it happy to be shortened?”
However, “When a lot of short members are lined up in a row, I’m glad that it becomes very short if I write it with members in the form of an expression.”
Please make use of it.