【问题标题】:Translate enum written in Java to C#将用 Java 编写的枚举转换为 C#
【发布时间】:2015-11-07 22:15:14
【问题描述】:

我正在翻译用 Java 编写的火星探测器问题的解决方案。我不确定如何处理找到 here 的 Direction 枚举类。

我不认为我可以在 C# 中做到这一点,因此我想问问是否有人可以建议如何做到这一点。

我正在考虑为从该接口继承的每个 Direction 创建一个 IDirection 接口和一个类。

【问题讨论】:

  • 您可以使用受保护的构造函数创建一个名为Direction 的类。然后在Direction里面为每个方向创建子类,在Direction类中为每个方向创建静态字段。或者,使用 this 等库。
  • 你能再解释一下或者给我一个代码示例吗?您是否还认为 Direction 类中的子类比从同一接口继承的 North、South、East、West 四个类更好。如果是,为什么?不好意思慢了,只是我还在学c#,想好好学。
  • 你是否将枚举序列化为 XML、Json 或二进制?
  • 子类化是不必要的,因为“左”意味着逆时针旋转(x, y) 90 度,这在数学上导致(-y, x)。同样“正确”的结果是(y, -x)

标签: java c# enums translate


【解决方案1】:

您可以为此目的使用struct,并选择一组代表标准方向的全局单例。我建议使用struct,因为您的Direction 对象具有值语义:

public struct Direction : IEquatable<Direction>
{
    short xstep;
    short ystep;

    public static Direction N { get { return new Direction(0, 1); } }
    public static Direction E { get { return new Direction(1, 0); } }
    public static Direction S { get { return new Direction(0, -1); } }
    public static Direction W { get { return new Direction(-1, 0); } }

    public static IEnumerable<Direction> Directions
    {
        get
        {
            yield return N;
            yield return E;
            yield return S;
            yield return W;
        }
    }

    Direction(int x, int y)
    {
        this.xstep = checked((short)x);
        this.ystep = checked((short)y);
    }

    public int XStep { get { return xstep; } }

    public int YStep { get { return ystep; } }

    public Direction Left { get { return new Direction(-YStep, XStep); } }

    public Direction Right { get { return new Direction(YStep, -XStep); } }

    public override bool Equals(object obj)
    {
        if (obj is Direction)
        {
            var other = (Direction)obj;
            return xstep == other.XStep && ystep == other.YStep;
        }
        return false;
    }

    public override int GetHashCode()
    {
        return (XStep.GetHashCode() | (YStep << 16).GetHashCode());
    }

    #region IEquatable<Direction> Members

    public bool Equals(Direction other)
    {
        return this.xstep == other.xstep && this.ystep == other.ystep;
    }

    #endregion

    public static Direction operator -(Direction direction)
    {
        return new Direction(-direction.XStep, -direction.YStep);
    }

    public static bool operator ==(Direction first, Direction second)
    {
        return first.Equals(second);
    }

    public static bool operator !=(Direction first, Direction second)
    {
        return !(first == second);
    }

    public override string ToString()
    {
        if (this == Direction.N)
            return "N";
        if (this == Direction.E)
            return "E";
        if (this == Direction.S)
            return "S";
        if (this == Direction.W)
            return "W";
        return string.Format("({0},{1}}", XStep.ToString(NumberFormatInfo.InvariantInfo), YStep.ToString(NumberFormatInfo.InvariantInfo));
    }
}

public static bool operator ==(Direction first, Direction second) 允许使用 == 运算符简单地比较方向。这也需要覆盖EqualsGetHashCode()

【讨论】:

  • 感谢您的建议,但是您将如何对这个类进行单元测试?
  • @Harry - 这不是一个类,它是一个struct。见Choosing Between Class and Struct。我不认为这实际上存在于 Java 中,请参阅Structs (C# vs Java)。基本上,结构是嵌入在堆栈或某些包含类中的自定义值类型,适用于轻量级、不可变数据。 (因为它类似于枚举。)
  • 不确定你在为单元测试做什么,但你可以做Debug.Assert(Direction.N.Left == Direction.W &amp;&amp; Direction.N.Right == Direction.E);之类的事情。
  • @Harry - 你需要序列化你的Direction吗?这里介绍的所有解决方案(具有私有构造函数和一组固定全局单例的不可变结构和类)都对序列化提出了挑战。
  • 不,我不需要序列化。我正在翻译问题中提供的链接中提供的代码。有没有办法简化这个?我仍然认为创建 4 个类更容易,每个方向一个类继承自 IDirection 并实现所有方法,例如 TurnLeft、TurnRight 和 Move。你怎么看?
【解决方案2】:

在 C# 中,枚举是一组有限原始类型的简单包装类型,遗憾的是扩展方法是扩展它们的唯一方法。
在 Java 中,它们是您可以使用自己的方法扩展的类。

您需要做的就是模仿这种行为。一种可能的方法是:

public sealed class Direction {

    public static readonly Direction N = new Direction(0, 1);
    public static readonly Direction S = new Direction(0, -1);
    public static readonly Direction E = new Direction(1, 0);
    public static readonly Direction W = new Direction(-1, 0);

    static Direction() {
        N.Left = W;
        N.Right = E;
        S.Left = E;
        S.Right = W;
        E.Left = N;
        E.Right = S;
        W.Left = S;
        W.Right = N;
    }

    private Direction(int stepSizeOnXAxis, int stepSizeOnYAxis)
    {
        StepSizeForXAxis = stepSizeOnXAxis;
        StepSizeForYAxis = stepSizeOnYAxis;
    }

    public Direction Right { get; private set; }
    public Direction Left { get; private set; }

    public int StepSizeForXAxis { get; }
    public int StepSizeForYAxis { get; }
}

【讨论】:

  • 感谢您的建议,但是您将如何对这个类进行单元测试?
  • 我会将它作为另一个使用它的类的一部分进行测试。这只是纯数据,例如测试Direction.N.Left == Direction.W 似乎是多余的。
【解决方案3】:

尽管 Java 似乎具有 C# 所没有的这一特性,但事实是(一如既往)C# 是一种更现代的语言,并且它需要更少的代码来产生相同的结果。

您的 72 行 java 代码可以翻译成这 35 行 C#:

public class Direction
{
    public static readonly Direction N = new Direction(0, 1);
    public static readonly Direction S = new Direction(0, -1);
    public static readonly Direction E = new Direction(1, 0);
    public static readonly Direction W = new Direction(-1, 0);

    private Direction(int stepSizeX, int stepSizeY)
    {
        this.StepSizeForXAxis = stepSizeX;
        this.StepSizeForYAxis = stepSizeY;
    }

    static Direction()
    {
        N.Left = W;
        N.Right = E;
        S.Left = E;
        S.Right = W;
        E.Left = N;
        E.Right = S;
        W.Left = S;
        W.Right = N;
    }

    public Direction Left { get; private set; }
    public Direction Right { get; private set; }
    public int StepSizeForXAxis { get; private set; }
    public int StepSizeForYAxis { get; private set; }
}

这导致一个类只能被自己实例化(因为私有构造函数),并且具有可以像使用 C# enum 一样使用的成员,具有附加属性的优势:

var south = Direction.S;
var east = south.Left;
Console.WriteLine(east == south); // True
Console.WriteLine(south.StepSizeForXAxis); //0
Console.WriteLine(south.StepSizeForYAxis); //-1

java 已经很难与 C# 相提并论了,更不用说声称比它有任何优势了,至少在语言层面上。

【讨论】:

  • 你需要一个静态构造函数:当你初始化N时,变量WE仍然是null。哦,还没有 C# 7 之类的东西 :)
  • @LucasTrzesniewski 解决了这个问题。
猜你喜欢
  • 2020-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-07
  • 2011-08-18
相关资源
最近更新 更多