Why I Like Ruby, Part 2: Blocks
blog.wekeroad.com
blog.wekeroad.com
C# example of blocks (loosely based upon Rob's examples):
//the action argument is the C# version of a block
// - by specifying Action<Artist> I'm stating that the block
// - will take 1 parameter, of type Artist
public void ParseKey(XDocument doc,
string elName,
Action<Artist> block)
{
//using XLinq instead of Nokogiri... *jealous*
foreach(var node in doc.Elements(elName))
{
var artist = new Artist{
Name = node.Element("Name").Value,
ArtistId = (int)node.Element("ArtistId").Value
};
block(artist);
}
}
//called by:
public void Main()
{
var doc = XDocument.Load("..\db\artists.xml");
ParseKey(doc, "Artist", artist=>{
//this is an anonymous method, the equiv
// of a Ruby block. "artist=>" is the equiv
// of |artist|
Db.Save(artist);
Console.WriteLine(artist.Name);
});
}
Certainly it is a bit cleaner in Ruby by way of:1) Nokogiri is super awesome.
2) Ruby's dynamicness means we don't have to have type ceremony everywhere.
That said, they're pretty equivalent in terms of functionality and expressiveness to me.
var thing () => {//code}
I think Anders is going to run out of symbols soon :).
The code you write here is fine - but you're tying Artist to the ParseKey method - which is the point of doing the block in the first place (to free that up). This might not look obtuse to you - but it's a lot more code than I have :).
Also - please don't forget the tie-in with method_missing; the reason it's nice is you're freeing your calling code from understanding the parser - which I don't think you can do here...
On the other hand, you're certainly right that the code I wrote is longer than yours. You are also correct that it ties itself to the Artist class, but that was because I was only exercising the use of C#'s version of blocks - not dynamic awesomesauce like method_missing. Method_missing is also possible to do in C# with .Net 4, as I'm sure you know.
A more complete rewrite of your example might be along the lines of:
//have to inherit from DynamicObject to get special dynamic treatment
public class DynamicXmlElement : DynamicObject
{
private XElement _element;
public DynamicXmlElement(XElement element)
{
_element = element;
}
//C# 4 equiv of method_missing
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if(_element.Element(binder.Name) == null)
return false;
result = _element(binder.Name).Value;
return true;
}
}
//changed this to use Action<dynamic>
public void ParseKey(XDocument doc, string elName, Action<dynamic> block)
{
foreach(var node in doc.Elements(elName))
block(new DynamicXmlElement(node));
}
public void Main()
{
var doc = XDocument.Load("..\db\music.xml");
ParseKey(doc, "Artist", artist=>{
Db.SaveArtist(artist.ArtistId, artist.Name);
Console.WriteLine(artist.Name);
});
ParseKey(doc, "Genre", genre=>{
Db.SaveGenre(genre.GenreId, genre.Name);
Console.WriteLine(genre.Name);
});
}
That said, yes, you can do this with less work/ceremony in Ruby as you've shown. I'm a big fan of Ruby and I'm glad you're showing MS devs what makes it so cool. I just don't want anyone to get the impression that some of these basic things are things that simply cannot be done in C#.You have to see in the code you write here...