英文:
Can't use static objects in a Switch statement in Unity
问题
我使用Unity 2021,所以它使用的是C#版本大于7,我相信。不知何故,我无法在Switch/Case语句中使用静态对象。
private Position getStartingPosition(Direction direction) {
switch (direction) {
case Direction.EAST:
return new Position(-1, height / 2);
case Direction.NORTH:
return new Position(width / 2, height);
case Direction.WEST:
return new Position(width, height / 2);
case Direction.SOUTH:
return new Position(width / 2, -1);
default:
throw new System.Exception("Impossible");
}
}
以及Direction类:
public class Direction
{
static public readonly Direction EAST = new Direction(1, 0);
static public readonly Direction NORTH = new Direction(0, -1);
static public readonly Direction WEST = new Direction(-1, 0);
static public readonly Direction SOUTH = new Direction(0, 1);
...
我收到的错误是:
Grid.cs(38,31): error CS1003: Syntax error, ':' expected
Grid.cs(38,31): error CS1513: } expected
Grid.cs(38,36): error CS1003: Syntax error, ':' expected
Grid.cs(38,36): error CS1513: } expected
Grid.cs(40,31): error CS1003: Syntax error, ':' expected
Grid.cs(40,31): error CS1513: } expected
我做错了什么?
英文:
I have Unity 2021 so it uses C# version > 7 I believe.
Somehow I can not use static objects in Switch/Case statement.
private Position getStartingPosition(Direction direction) {
switch (direction) {
case Direction Direction.EAST:
return new Position(-1, height / 2);
case Direction Direction.NORTH:
return new Position(width / 2, height);
case Direction Direction.WEST:
return new Position(width, height / 2);
case Direction Direction.SOUTH:
return new Position(width / 2, -1);
default:
throw new System.Exception("Impossible");
}
}
and the Direction class:
public class Direction
{
static public readonly Direction EAST = new Direction(1, 0);
static public readonly Direction NORTH = new Direction(0, -1);
static public readonly Direction WEST = new Direction(-1, 0);
static public readonly Direction SOUTH = new Direction(0, 1);
...
The error I am getting is:
Grid.cs(38,31): error CS1003: Syntax error, ':' expected
Grid.cs(38,31): error CS1513: } expected
Grid.cs(38,36): error CS1003: Syntax error, ':' expected
Grid.cs(38,36): error CS1513: } expected
Grid.cs(40,31): error CS1003: Syntax error, ':' expected
Grid.cs(40,31): error CS1513: } expected
What am I doing wrong?
答案1
得分: 2
case
语句应该是var _ when direction.Equals(Class.VALUE)
,不需要声明。但是Direction
是一个对象,所以可以使用以下语句之一:
switch (direction) {
case var _ when direction.Equals(Direction.EAST):
return new Position(-1, height / 2);
case var _ when direction.Equals(Direction.NORTH):
return new Position(width / 2, height);
case var _ when direction.Equals(Direction.WEST):
return new Position(width, height / 2);
case var _ when direction.Equals(Direction.SOUTH):
return new Position(width / 2, -1);
default:
throw new System.Exception("Impossible");
}
并实现接口 IEquatable<Direction>
,方法类似于以下内容:
public bool Equals(Direction otherDirection)
{
return (this.x == otherDirection.x && this.y == otherDirection.y);
}
其中,x
和 y
是您的类中用于判断两个对象是否相等的值。
英文:
The case
statment should be var _ when direction.Equals(Class.VALUE)
without the declaration. But also Direction
is an object so one option can be use this statment:
switch (direction) {
case var _ when direction.Equals(Direction.EAST):
return new Position(-1, height / 2);
case var _ when direction.Equals(Direction.NORTH):
return new Position(width / 2, height);
case var _ when direction.Equals(Direction.WEST):
return new Position(width, height / 2);
case var _ when direction.Equals(Direction.SOUTH):
return new Position(width / 2, -1);
default:
throw new System.Exception("Impossible");
}
And implement the interface IEquatable<Direction>
with a method similar to this:
public bool Equals(Direction otherDirection)
{
return (this.x == otherDirection.x && this.y == otherDirection.y);
}
Where x
and y
are values into your class used to know if two objects are equals.
答案2
得分: 1
只有在常量和模式上才能进行切换(其中常量被视为常量模式)。Unity使用C# 9.0提供了强大的模式匹配表达式。
自C# 9.0以来,我们拥有了与switch语句相比语法更简化的switch表达式。因此,我建议与模式匹配一起使用switch表达式。
我们可以使用位置模式进行测试。要使用它,我们必须为类添加解构器,如下所示:
public class Direction
{
public Direction(int east, int south)
{
East = east;
South = south;
}
// 你没有展示整个类。
// 我假设它有两个用于主要方向的属性。
public int East { get; }
public int South { get; }
public void Deconstruct(out int east, out int south)
{
east = East;
south = South;
}
}
然后我们可以像这样进行切换:
// 使用解构器的位置模式
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)),
};
另一种可能的模式是元组模式,不需要解构器:
// 元组模式
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)),
};
还有一种可能性是使用枚举常量进行切换,使用常量模式:
public enum DirectionKind
{
None,
East,
North,
West,
South
}
然后,我们为Direction
类添加一个类似以下的属性:
public DirectionKind DirectionKind { get; }
我让你自行初始化它。然后我们可以这样切换:
// 对枚举常量的常量模式切换
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)),
};
属性模式不需要特殊的基础设施:
// 属性模式
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)),
};
还有一种类型模式。如果我们将方向声明为一个类层次结构,可以使用它。
public abstract class Direction
{
public abstract int East { get; }
public abstract int South { get; }
}
public class EastDirection : Direction
{
private EastDirection() { } // 隐藏构造函数以实现单例。
public static readonly Direction Instance = new EastDirection();
public override int East => 1;
public override int South => 0;
}
// 其他Direction类的定义...
// 类型模式
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)),
};
注意:我在这里使用了单例模式作为建议。对于switch表达式,它并不是必需的。
这个类层次结构甚至可以通过在Direction
中添加一个抽象的GetPosition
方法来完全消除switch表达式。
public abstract Position GetPosition(int width, int height);
作为示例,WestDirection
会实现它:
public override Position GetPosition(int width, int height)
{
return new Position(width, height / 2);
}
给定一个方向,你可以这样获取一个位置:
Direction direction = ...;
Position position = direction.GetPosition(width, height);
这是解决问题的真正面向对象的方式。
使用target typed new,我们可以这样写(以位置模式为例):
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)),
};
英文:
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)),
};
答案3
得分: 0
已经在这里得到答案:
https://stackoverflow.com/questions/12429949/switch-statement-with-static-fields
我将其更改为
switch (direction) {
case var _ when direction == Direction.EAST:
return new Position(-1, height / 2);
case var _ when direction == Direction.NORTH:
return new Position(width / 2, height);
case var _ when direction == Direction.WEST:
return new Position(width, height / 2);
case var _ when direction == Direction.SOUTH:
return new Position(width / 2, -1);
default:
throw new System.Exception("不可能的情况");
}
英文:
Was already answered here:
https://stackoverflow.com/questions/12429949/switch-statement-with-static-fields
I changed it to
switch (direction) {
case var _ when direction == Direction.EAST:
return new Position(-1, height / 2);
case var _ when direction == Direction.NORTH:
return new Position(width / 2, height);
case var _ when direction == Direction.WEST:
return new Position(width, height / 2);
case var _ when direction == Direction.SOUTH:
return new Position(width / 2, -1);
default:
throw new System.Exception("Impossible");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论