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.

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. Commented Nov 7, 2015 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. Commented Nov 7, 2015 at 22:32
  • Do you ever serialize the enum to XML, Json or binary? Commented Nov 7, 2015 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). Commented Nov 7, 2015 at 23:02

3 Answers 3

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().

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for your suggestion, but how would you unit test this class?
@Harry - It's not a class, it's a struct. See Choosing Between Class and Struct. I don't think this actually exists in Java, see Structs (C# vs Java). 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.)
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);.
@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.
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?
|
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; } } 

2 Comments

Thanks for your suggestion, but how would you unit test this class?
I'd test it as a part of another class which uses it. It's just pure data, and testing for instance that Direction.N.Left == Direction.W seems redundant.
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.

2 Comments

You need a static constructor: When you initialize N, the variables W and E are still null. Oh, and there's no such thing as C# 7 yet :)
@LucasTrzesniewski fixed that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.