Home > Software design >  Can someone help me understand anonymous functions in C#?
Can someone help me understand anonymous functions in C#?

Time:10-30

I'm currently following a Unity course. In one of the lessons, the lecturer uses an anonymous function that I'm having trouble understanding.

Here's the relevant code:

public EnemyAIAction GetBestEnemyAIAction()
{
    List<EnemyAIAction> enemyAIActionList = new List<EnemyAIAction>();
    List<GridPosition> validActionGridPositionList = GetValidActionGridPositionList();

    foreach(GridPosition gridPosition in validActionGridPositionList)
    {
        EnemyAIAction enemyAIAction = GetEnemyAIAction(gridPosition);
        enemyAIActionList.Add(enemyAIAction);
    }

    enemyAIActionList.Sort((EnemyAIAction a, EnemyAIAction b) => b.actionValue - a.actionValue);
}

The lecturer doesn't bother explaining why this approach sorts the list by actionValue. I'm having trouble understanding how subtracting the inputs from each other sorts the list.

I would greatly appreciate it if someone could help me understand what's going on in that line of code. Thanks in advance.

I simply don't understand the code.

CodePudding user response:

The Sort method is declared as

public void Sort (Comparison<T> comparison);

Comparison<T> is declared as

public delegate int Comparison<in T>(T x, T y);

According to the documentation, it returns A signed integer that indicates the relative values of x and y, as shown in the following table.

Value Meaning
Less than 0 x is less than y.
0 x equals y.
Greater than 0 x is greater than y.

I.e., the Sort method expects a delegate. You can think of a delegate as the address of a function. In this specific case the method accepts two items of the list as input parameters. The return value is a negative int when x is less than y, 0 when both items are considered as equal, and a positive int when x is greater than y.

Now you could declare your own method like this to sort in ascending order:

int ActionListComparison(EnemyAIAction x, EnemyAIAction y)
{
    if (x.actionValue > y.actionValue) return  1;
    if (x.actionValue < y.actionValue) return -1;
    return 0; // both are equal
}

Since it does not matter how large the result is (only the sign matters), you could simply write

int ActionListComparison(EnemyAIAction x, EnemyAIAction y)
{
    return x.actionValue - y.actionValue;
}

Then call the Sort method like this:

enemyAIActionList.Sort(ActionListComparison);

Note that no braces must follow ActionListComparison() because we are not calling the method here, we are passing the method itself as a parameter to Sort. Sort then calls this method on many pairs of list items according to a sorting algorithm (e.g., Quick Sort) until the list is sorted.

Now, there is a shortcut in defining this method: you can use a lambda expression. A lambda expression is a very concise syntax for declaring an anonymous method on the fly.

So (x, y) => x.actionValue - y.actionValue is equivalent to the method above. The type of the parameters is inferred from the declaration int Comparison<in T>(T x, T y) and T is given in the declaration of the list. So, you do not need to specify it as in the example you have given. (Note that the names you give to the parameters does not matter. Specifically, they do not need to be the same as in the declaration of Comparison.)

If you want to sort in descending order, just swap the signs, i.e., swap the values in the subtraction.

  • Related