无法在Unity的Switch语句中使用静态对象。

huangapple go评论75阅读模式
英文:

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);  
}

其中,xy 是您的类中用于判断两个对象是否相等的值。

英文:

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(&quot;Impossible&quot;);
}

And implement the interface IEquatable&lt;Direction&gt; with a method similar to this:

public bool Equals(Direction otherDirection)  
{  
    return (this.x == otherDirection.x &amp;&amp; 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) =&gt; new Position(-1, height / 2),
    ( 0, -1) =&gt; new Position(width / 2, height),
    (-1,  0) =&gt; new Position(width, height / 2),
    ( 0,  1) =&gt; new Position(width / 2, -1),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, nameof(direction)),
};

Another possible pattern is the tuple pattern not requiring a deconstructor:

// Tuple pattern
return (direction.East, direction.South) switch {
    ( 1,  0) =&gt; new Position(-1, height / 2),
    ( 0, -1) =&gt; new Position(width / 2, height),
    (-1,  0) =&gt; new Position(width, height / 2),
    ( 0,  1) =&gt; new Position(width / 2, -1),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, 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  =&gt; new Position(-1, height / 2),
    DirectionKind.North =&gt; new Position(width / 2, height),
    DirectionKind.West  =&gt; new Position(width, height / 2),
    DirectionKind.South =&gt; new Position(width / 2, -1),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, nameof(direction)),
};

The property pattern does not require a sepcial infrastructure:

// Property pattern
return direction switch { 
    { East:  1, South:  0 } =&gt; new Position(-1, height / 2), 
    { East:  0, South: -1 } =&gt; new Position(width / 2, height),
    { East: -1, South:  0 } =&gt; new Position(width, height / 2), 
    { East:  0, South:  1 } =&gt; new Position(width / 2, -1),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, 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 =&gt; 1;
    public override int South =&gt; 0;
}

public class NorthDirection : Direction
{
    private NorthDirection() { }

    public static readonly Direction Instance = new NorthDirection();

    public override int East =&gt; 0;
    public override int South =&gt; -1;
}

public class WestDirection : Direction
{
    private WestDirection() { }

    public static readonly Direction Instance = new WestDirection();

    public override int East =&gt; -1;
    public override int South =&gt; 0;
}

public class SouthDirection : Direction
{
    private SouthDirection() { }

    public static readonly Direction Instance = new SouthDirection();

    public override int East =&gt; 0;
    public override int South =&gt; 1;
}
// Type pattern
return direction switch {
    EastDirection =&gt; new Position(-1, height / 2),
    NorthDirection =&gt; new Position(width / 2, height),
    WestDirection =&gt; new Position(width, height / 2),
    SouthDirection =&gt; new Position(width / 2, -1),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, 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) =&gt; new (-1,        height / 2),
    ( 0, -1) =&gt; new (width / 2, height    ),
    (-1,  0) =&gt; new (width,     height / 2),
    ( 0,  1) =&gt; new (width / 2, -1        ),
    _ =&gt; throw new ArgumentException(&quot;Impossible&quot;, 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(&quot;Impossible&quot;);
    }

huangapple
  • 本文由 发表于 2023年1月8日 22:55:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75048744.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定