Using the Power of LINQ to Easily Manage Collections of Objects [Awesome] | Posted at 4:15 PM
I am currently working a WPF BlackJack implementation to further develop my object-oriented and .NET skills. I have a great book called VB 2008 Recipes. It’s all sorts of useful and I recently came across a super great way to manage my annoying collections of cards, players, etc. in the game.
Instead of implementing interfaces like IList or IEnumerator for, say, a Hand of cards, you can create a variable/property called Cards with a type List(Of Card). This creates a generic list of objects of type Card (your card class, or any other type of class you want a collection of).
Then, as in my case, you can perform some powerful functions that would otherwise take more lines of code to do. For example, in BlackJack an Ace can be valued as either 1 or 11, depending on whether or not it will make the Hand total over 21 (a bust).
The way I calculate the total value for a hand, I calculate the total of all non-ace cards and then calculate the total of the Aces based on that other total.
Here was the original code I used before implementing LINQ:
Dim Cards() As Card Dim hasAces as Boolean = False ' Calculate total for non-Ace cards For Each myCard As Card In Cards Select Case myCard.Rank Case Card.RankType.Ace ' Aces hasAces = True Case Else intTotal += myCard.Value End Select Next If hasAces Then ' Do the same thing as above, only select case Ace ' and figure out the total End If
That is a simplified version. Now, witness the power of LINQ combining that Select statement into a single line!
Imports System.LINQ.Enumerable [...] Dim Cards As List(Of Card) ' Calculate total for non-Ace cards ' PS. I <3 LINQ intTotal = Cards.Where(Function(c) c.Rank <> Card.RankType.Ace).Sum(Function(c) c.Value) ' Any Aces? If Cards.Any(Function(c) c.Rank = Card.RankType.Ace) Then End If
As you can see, WAY more manageable! The reason LINQ can do this is because the System.Linq.Enumerable namespace has Extension methods like Sum, Where, Average, Max, Min, etc. that work with any kind of collection.
Previously, I was aware of LINQ to SQL and how great that was, but I didn't realize LINQ also worked with Objects (hence, LINQ to Objects).
Like I said earlier, instead of making my Hand class implement an IList, etc. I can just make Cards a property so that when I need to add a card, retrieve a card, etc from an external class, all I need to do is:
MyHand.Cards.Add(new Card) or MyHand.Cards(0)
If you want more information about LINQ to Objects, check it out on MSDN!