You can only switch on constants and patterns (where a constant is considered as a constant pattern). Unity uses C# 9.0 providing powerful pattern matching expressions.
Since C# 9.0 we have the switch expression with a simplified syntax compared to the switch statement. I therefore suggest using switch expressions in conjunction with pattern matching.
We can use a positional pattern to do the test. To use it we must add a deconstructor to the class
public class Direction
{
public Direction(int east, int south)
{
East = east;
South = south;
}
// You have not shown your whole class.
// I assume that it has two properties for the main directions.
public int East { get; }
public int South { get; }
public void Deconstruct(out int east, out int south)
{
east = East;
south = South;
}
}
Then we can switch like this:
// Positional pattern with deconstructor
return direction switch {
( 1, 0) => new Position(-1, height / 2),
( 0, -1) => new Position(width / 2, height),
(-1, 0) => new Position(width, height / 2),
( 0, 1) => new Position(width / 2, -1),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};
Another possible pattern is the tuple pattern not requiring a deconstructor:
// Tuple pattern
return (direction.East, direction.South) switch {
( 1, 0) => new Position(-1, height / 2),
( 0, -1) => new Position(width / 2, height),
(-1, 0) => new Position(width, height / 2),
( 0, 1) => new Position(width / 2, -1),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};
Yet another possibility is to switch on enum
constants using a constant pattern:
public enum DirectionKind
{
None,
East,
North,
West,
South
}
We then add a property like the following one to the Direction
class
public DirectionKind DirectionKind { get; }
I leave it up to you to initialize it. Then we switch like this:
// Constant pattern on enum constants
return direction.DirectionKind switch {
DirectionKind.East => new Position(-1, height / 2),
DirectionKind.North => new Position(width / 2, height),
DirectionKind.West => new Position(width, height / 2),
DirectionKind.South => new Position(width / 2, -1),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};
The property pattern does not require a sepcial infrastructure:
// Property pattern
return direction switch {
{ East: 1, South: 0 } => new Position(-1, height / 2),
{ East: 0, South: -1 } => new Position(width / 2, height),
{ East: -1, South: 0 } => new Position(width, height / 2),
{ East: 0, South: 1 } => new Position(width / 2, -1),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};
There is also a type pattern. It can be used if we declare the directions as a class hierarchy.
public abstract class Direction
{
public abstract int East { get; }
public abstract int South { get; }
}
public class EastDirection : Direction
{
private EastDirection() { } // Hide constructor to implement a singleton.
public static readonly Direction Instance = new EastDirection();
public override int East => 1;
public override int South => 0;
}
public class NorthDirection : Direction
{
private NorthDirection() { }
public static readonly Direction Instance = new NorthDirection();
public override int East => 0;
public override int South => -1;
}
public class WestDirection : Direction
{
private WestDirection() { }
public static readonly Direction Instance = new WestDirection();
public override int East => -1;
public override int South => 0;
}
public class SouthDirection : Direction
{
private SouthDirection() { }
public static readonly Direction Instance = new SouthDirection();
public override int East => 0;
public override int South => 1;
}
// Type pattern
return direction switch {
EastDirection => new Position(-1, height / 2),
NorthDirection => new Position(width / 2, height),
WestDirection => new Position(width, height / 2),
SouthDirection => new Position(width / 2, -1),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};
Note: I used the singleton pattern here as a suggestion. I is not required for the switch expression.
This class hierarchy gives us even a way to eliminate the switch expression altogether by adding an abstract GetPosition
method to Direction
.
public abstract Position GetPosition(int width, int height);
As an example WestDirection
would implement it like this:
public override Position GetPosition(int width, int height)
{
return new Position(width, height / 2);
}
Given a direction you can get a position like this
Direction direction = ...;
Position position = direction.GetPosition(width, height);
This is the true OOP way to solve the problem.
With target typed new we can write (with the positional pattern as an example):
return direction switch {
( 1, 0) => new (-1, height / 2),
( 0, -1) => new (width / 2, height ),
(-1, 0) => new (width, height / 2),
( 0, 1) => new (width / 2, -1 ),
_ => throw new ArgumentException("Impossible", nameof(direction)),
};