Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Tuesday, April 28, 2015

Random Annoyance: The C# Delegate Interview Question almost Nobody Gets

Part of my job is to interview other software developers, roughly 3-5 a week.  I hate to be "that guy" who nitpicks interview question responses.  Usually I am very patient and more interested with how candidates think, rather than what they happen to know today.  I try to work with that nervous person on the other end of the line to help them shine.  But one question I ask is almost never answered very well:

In C#, what is a delegate?

I find this question is answered in the following ways:

-15% "I don't know."
-5% "It's used for events but I don't remember more than that."
-79+% "It's like a function pointer like in [insert C or C-derived language here].  You use them for events."
-<1% "A delegate is a type that represents references to methods with a particular parameter list and return type.  You can do all kinds of things with them like event handling, multi-threading..."

Of the 80% that conceptualize C# delegates as pointer-ish, maybe 5% can answer what an anonymous delegate is.  Even a high percentage of developers that are using Linq methodically or lambda syntax generally don't recognize their own use of anonymous delegates.  When I probe with followup questions, I find it's not just an issue of not knowing the terminology but rather not really understanding conceptually what's happening.

I wouldn't say this question is necessarily a litmus test for me, but I feel strongly that questions like this tell me the depth of your "passion" for making the most of your tools.  How curious are you about the tools you have in your toolbox?  Are you constantly looking for new and creative ways to use those tools?  To abuse the 80/20 rule, sure--80% of the time just knowing a delegate is "like a pointer" and being able to use lambda syntax without understanding it will allow you to solve the problem and keep the project moving.  It's that 20% of the time (and probably much less than that) when really knowing what your tools are capable of is when you can shine and really produce an elegant solution and save the team a lot of time and grief.

Long story short, I've never not recommended hiring someone who answered my delegates question well.  As they say, RTFM ;-)




Thursday, April 9, 2015

Adding Action to your .Add

I've learned not to be intimidated by C#'s rich library for delegate and lambda operations.  In fact, I've come to embrace Func and Action as tools to simplify APIs and keep my code clean.  One pattern I really liked when I first saw it, and try to encourage its use, is offering an override along the lines of .Add<T>(Action<T> aNewT) any time an API exposes the ability to add something to a collection.

The vendors of server-side web controls all use this pattern for adding columns to a grid control. First consider the delegate-less approach:

GridColumn myColumn = new GridColumn();
myColumn.Title = "Name";
myColumn.Sortable = true;
myColumn.Filterable = true;
etc...

mySuperGrid.Columns.Add(myColumn);

Maybe we can clean things up a little by declaring the new anonymous object within .Add method call:

mySuperGrid.Columns.Add(new GridColumn() 
{
      Title = "Name";
       etc...
});
But most of the time, won't I always want to add a new object?  So why make me bother to type "new"?  And if I can only add GridColumn types, why make me type that too?  So consider the following override for the .Add method:

public void Add(Action<GridColumn> initializerDelegate)
{
       GridColumn newColumn = new GridColumn();
       //We could even do some default intialization if it wasn't already done in GridColumn's 
       //constructor...
       newColumn.myProperty=myDefaultValue;
       
       initializerDelegate(newColumn);

       myColumnCollection.Add(newColumn);
}

Now look what a consumer of the API can do:

mySuperGrid.Columns.Add(column=>
{
      column.Title="Name";
      column.Sortable=true;
      etc..
});

In my opinion, this is much cleaner and simpler for consumers of the .Add method.  Note the consumer doesn't have to know the name of the type used to represent a new column, nor worry about correctly instantiating a new instance of one. Compile-time binding and Intellisense still apply!

So don't fear "=>", it really is your friend!