In addition to the great answer provided by Fernando Matsumoto you should consider implementing the equality/hashcode methods/operators. Reference equality isn't how cards are treated in the real world. In the real world it doesn't matter which deck the Jack of Clubs came from it is always a Jack of Clubs.
public class Card : IEquatable<Card>
{
public Card(CardSuit suit, CardRank rank)
{
// Suit and Rank validation logic here
Suit = suit;
Rank = rank;
}
// Replace this with the plain get call like Fernando's answer in C# 6
// You can also leave it and be careful or create a private readonly backing property
public CardSuit Suit { get; private set; }
public CardRank Rank { get; private set; }
public static bool operator ==(Card left, Card right)
{
// Review https://msdn.microsoft.com/en-US/library/ms173147%28v=vs.80%29.aspx
// If both are null, or both are same instance, return true.
if (ReferenceEquals(left, right))
{
return true;
}
// If one is null, but not both, return false.
if (((object)left == null) || ((object)right == null))
{
return false;
}
// Return true if the fields match:
return left.Equals(right);
}
public static bool operator !=(Card left, Card right)
{
return !(left == right);
}
public bool Equals(Card other)
{
if(other == null)
{
return false;
}
return Rank == other.Rank && Suit == other.Suit;
}
public override bool Equals(object obj)
{
return Equals(obj as Card);
}
public override int GetHashCode()
{
return Suit.GetHashCode() ^ Rank.GetHashCode();
}
// Not strictly needed but why not do it....
public override string ToString()
{
// Take advantage of how the Enum.ToString() method functions
return Rank.ToString() + " of " + Suit.ToString();
}
}
Something else you might consider is implementing the IComparable<Card>
interface. That would let you sort a user's hand trivially. I'll leave that exercise to you because I don't want to debate what is the proper suit order1.
This is fairly nit-picky that has more to do with domain knowledge than OOP. The order you specify your suits is up to you but I'd recommend alternating the color of the suits. When you display the hand to the user alternating colors help the users distinguish Hearts from Diamonds, and Spades from Clubs. Respecting this in the CardSuit
enum will make the sorting/comparison logic easier.
If you do this then you should keep in mind that you're encoding implicit knowledge into the enum. Since the enum should be extremely stable this implicit knowledge feels like a reasonable trade-off to writing a suit order extension method, suit wrapper with an order value, or an external IComparer<Suit>
implementation which must be specified for each comparison/sort.
1: Even though it is clearly Spades, Diamonds, Clubs, Hearts... ;)