2

I am translating a solution to the Mars Rover problem written in Java. I am not sure how to deal with the Direction enum class found here.

I don't think I can do it like that in C#, therefore I would like to ask if anyone could suggest how to do this.

I was thinking of making an IDirection interface and a class for each Direction that inherits from that interface.

Harry
  • 33
  • 4
  • You could make a class named `Direction` with a protected constructor. Then create subclasses inside the Direction for each direction, and create static fields in the Direction class for each direction. Alternatively, use a library such as [this](https://github.com/HeadspringLabs/Enumeration). – cbr Nov 07 '15 at 22:22
  • Can you explain that a bit more or give me an example in code please? Also do you think subclasses inside the Direction class is better than having 4 classes, being North, South, East, West that inherit from the same interface. If yes, why? Sorry for being slow, it's just that I'm still learning c# and I want to learn it right. – Harry Nov 07 '15 at 22:32
  • Do you ever serialize the enum to XML, Json or binary? – dbc Nov 07 '15 at 22:59
  • Subclassing is unnecessary, since "left" means rotating `(x, y)` 90 degrees counterclockwise, which results mathematically in in `(-y, x)`. Similarly "right" results in `(y, -x)`. – dbc Nov 07 '15 at 23:02

3 Answers3

2

Despite the fact that java seems to have this feature which C# doesn't, the reality is (as always) that C# is a much more modern language, and it requires much less code to produce the same results.

Your 72 lines of java code can be translated into these 35 lines of 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; }
}

This results in a class that can only be instantiated by itself (because of the private constructor), and has members that you can use in the same way you would use a C# enum, with the advantage of the additional properties:

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

java can be hardly compared to C# anymore, let alone claim any advantage over it, at least at the language level.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
2

In C# enums are simple wrapper types over a finite set of primitive types, and sadly extension methods are the only way to extend them.
In Java, they're classes which you can extend with their own methods.

All you need to do is emulate that behavior. A possible approach could be:

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; }
}
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
2

You could use a struct for this purpose, with a selected set of global singletons representing standard directions. I suggest a struct since your Direction object has value semantics:

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

The public static bool operator ==(Direction first, Direction second) allows directions to be compared simply using the == operator. This also requires overriding Equals and GetHashCode().

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thanks for your suggestion, but how would you unit test this class? – Harry Nov 07 '15 at 23:11
  • @Harry - It's not a class, it's a [struct](https://msdn.microsoft.com/en-us/library/ms173109.aspx). See [Choosing Between Class and Struct](https://msdn.microsoft.com/en-us/library/ms229017%28v=vs.110%29.aspx). I don't think this actually exists in Java, see [Structs (C# vs Java)](https://msdn.microsoft.com/en-us/library/ms228600.aspx). Basically a struct is a custom value type that is embedded on the stack or some containing class and is appropriate for lightweight, immutable data. (In that it resembles an enum.) – dbc Nov 07 '15 at 23:17
  • Not sure what you're doing for unit testing, but you can do things like `Debug.Assert(Direction.N.Left == Direction.W && Direction.N.Right == Direction.E);`. – dbc Nov 07 '15 at 23:21
  • @Harry - do you ever need to serialize your `Direction`? All of the solutions presented here (immutable structs and classes with private constructors and a fixed set of global singletons) present challenges for serialization. – dbc Nov 07 '15 at 23:24
  • No, I don't need do serialization. I'm translating the code provided in the link provided in the question. Is there a way to simplify this? I still think it's easier to to create 4 classes, one for each direction inheriting from IDirection and implementing all the methods such as TurnLeft, TurnRight and Move. What do you think? – Harry Nov 07 '15 at 23:43
  • @Harry - it looks complicated because overriding equality in c# is a bit of a nuisance. See [Guidelines for Overriding Equals() and Operator == (C# Programming Guide)](https://msdn.microsoft.com/en-US/library/ms173147.aspx). I suppose you could take out the flip operator (`public static Direction operator -(Direction direction)`), I put it in because it seemed sensible to have. – dbc Nov 07 '15 at 23:53
  • @Harry - see also [C# vs Java Enum (for those new to C#)](http://stackoverflow.com/questions/469287/c-sharp-vs-java-enum-for-those-new-to-c). – dbc Nov 07 '15 at 23:55
  • This is a good solution, but be aware that a `struct` implies an empty public default constructor, which means you can write `new Direction()` in your code (and you'll get a direction with both steps equal to `0`). – Lucas Trzesniewski Nov 08 '15 at 11:34