(This one is maybe more of a 10 min post. you'll survive)
Lots of code in this one, so I'll cut to the chase. I have a woman. Shocking i know. Right now your thinking "But Dave, your such an awesome code ninja! how could you allow yourself to be tied down" (you didn't know i was a mind reader too did ya). To that i have to say, My womans job is to:
- Fill the fridge
- Get me beer
I know, isn't she lucky? I appreciate my wife so much that i will show you here how i have immortalized her in code. Not only that, but I've made her more efficient!
Like I said, she fills the fridge, here are some of the things she fills it with.
public abstract class FridgeCrap{ }
public abstract class Drink : FridgeCrap
{
public abstract void Consume();
}
public class Beer : Drink
{
public override void Consume()
{
Console.WriteLine("Glug glug glug.... mmmmmm beer.");
}
}
public class Water : Drink
{
public override void Consume()
{
Console.WriteLine("Although this tastes like Coors Lite, it's not, it's water.");
}
}
public class UnEdableFood :FridgeCrap
{
public void Disclaimer()
{
Console.WriteLine("There is enough bacteria in this meat that they qualify as their own township.");
}
}
public class Cheese : FridgeCrap
{
public void Eat()
{
Console.WriteLine("Does anything go better with beer?");
}
}
And of course i need my woman! so here is her finely shaped self; formatted in C# of course.
public class Woman
{
private List<FridgeCrap> TheFridge = new List<FridgeCrap>();
private Random r = new Random();
public Woman()
{
int j;
//Fill the fridge with random stuff,
//just like you do on dollar day at the "Day Old"
//bakery
for (int i = 0; i < 100; i++)
{
j = r.Next(3);
//Switches are bad...but i'm lazy.
switch (j)
{
case 1:
TheFridge.Add(new Water());
break;
case 2:
TheFridge.Add(new Beer());
break;
case 3:
TheFridge.Add(new UnEdableFood());
break;
}
}
}
public void ShakeIt()
{
Console.WriteLine("shake shake shake, shake your groove thang...");
}
}
Now, like i said, it's her job to fill the fridge, you can see that when she gets up and initializes, she fills the thing. Just like a squirrel hiding food for winter, she stuffs that thing. Her other job is to get me the beers from the fridge. So here is what i *Could* ask of her
public List<Beer> GatherMyBeer()
{
List<Beer> retval = new List<Beer>();
foreach (FridgeCrap crap in TheFridge)
{
//Let me show you how i can make beer from crap!
if (crap as Beer !=null)
retval.Add((Beer)crap);
}
return retval;
}
Wait!?! What the hell is wrong here?! I have to wait for her to look through the ENTIRE damn fridge before i can have a beer!?!? thats absurd!!!, so i know what I'll do! Ah HA! The Power and the Glory of C#!
public IEnumerable<Beer> BringMeBeer()
{
foreach (FridgeCrap crap in TheFridge)
{
//Beer from crap sounds bad, so let me show you how i
//can //decern from crap and beer
if (crap as Beer !=null)
yield return (Beer)crap;
}
}
yield return? WTF is that you ask? I would say "Look, you knew it was coming, it's in the frigging title".
Think of yield return as if the current code block is yielding itself to the calling code. Meaning that it has found a result, and is returning that result and will continue when the calling code lets it.
public class Dave
{
private Woman Wife = new Woman();
private void IWantBeer()
{
foreach (Beer SamAdams in Wife.BringMeBeer())
{
SamAdams.Consume();
}
}
}
In beer/woman terms that means, while my wife is gathering beer, she will get a beer, bring it to me, let me finish it and immediately hand me another beer from the fridge. Life is good, no?
The best part about this? Were just returning a generic IEnumerable of Beer. What if we could change this method to return Anything that could be in the fridge! Or ANYTHING for that matter!? Simple, check this out...
public IEnumerable<T> GetMeSomething<T>() where T : FridgeCrap
{
foreach (FridgeCrap crap in TheFridge)
if (crap as T!=null)
yield return (T)crap;
}
How sexy is that? That is a Generic Method and that where thingy dangling off the edge of the method there? Thats a predicate. T represents a type. The predicate does a couple of things for me. For one, it restricts the types I can pass in as T to anything of FridgeCrap type, secondly, it lets me cast my members as the generic T. Take that off, and the crap as T line and the (T)crap line will both break. I won't go any further with this, it's really a topic for another post.
So check out this sexy code...
private void IWantBeer()
{
foreach (Beer SamAdams in Wife.GetMeSomething<Beer>())
SamAdams.Consume();
}
private void IWantWater()
{
//Sif, as if this would ever happen
foreach (Water w in Wife.GetMeSomething<Water>())
w.Consume();
}
Now, your thinking "Dave, your so cool, and your code is SO sexy, how can I be like you and get all the ladies?" Well, I will tell you. Come to the Ann Arbor .Net Developers meetings. Second Wed. of each month. While it's true, I am awesome, and my code is just as cool, I didn't learn everything on my own. I spoke with people at the meetings, I listened, and I wallowed in toxic waste. That is how I gained these super coding powers!
If you find errors in my code, it would be the fault of the poorly trained monkey that I am dictating this post to.
Happy Holidays if i don't post sooner
Dave Redding
VP, Ann Arbor .Net Developers
P.S. My wife doesn't read my blog, thats how I get away with this. Cheers!