The Enumerable.Select method is used in LINQ to perform query magic. It may also be used in scenarios where you wish to transform a collection.
The most common use to which I put this is in mapping between domain and message objects. The system I'm currently working with maintains a clear distinction between the wire format and the domain. This requires that there be a mapping between the formats. This is performed by a series of mapper classes that handle mapping between different message and domain types. This is composable, for instance an address mapper may be injected into multiple classes that have an address element to be mapped.
In doing the mapping it is often desirable to take a collection in one form and map it to the other. Pre-.NET 3.5 this tended to be done with foreach loops. This works perfectly well but it tends to be verbose. Select allows this to be expressed much more succinctly. The following example maps a collection of type BusinessObject to a collection of type MessagePart and includes it in the message (of type Message) using an object initialiser (which is not a necessary component but is included to indicate a common context).
var message = new Message
{
MessageParts = businessObjects.Select(businessObject => _mapper.MapToMessage(businessObject)).ToList()
};
This neatly encapsulates everything required to transform the collections into a single line. Previously the code would have looked something like this:
var message = new Message();
message.MessageParts = new List<MessagePart>();
foreach (var businessObject in businessObjects)
{
message.MessageParts.Add(_mapper.MapToMessage(businessObject));
}
This is more verbose and in my opinion less maintainable. It requires the reader of the code to look at took much code for such a simple action. In some cases it may ever warrant extraction into it's own method. The Select based example by contrast is clearly assigning the MessageParts element of the Message. This is much easier to skim over if this is not the item of interest and expresses clearly the operation of the mapping when it is. All it requires is a basic understanding of extension methods and lamdba expressions.
As a side note, the MessageParts collection of Message is a list property with a setter which is generally frowned upon. This is acceptable in this case because message objects are a wire format that need a serialisation and deserialisation process. This tends to necessitate the setting of the collection directly. Messages don't carry business logic and are transient so the risks of a settable collection do not generally apply. Such properties should not be located on business objects where the contents of collections generally need more control. Business objects should expose appropriate methods for adding to their collections where this is necessary as this allows enforcement of the appropriate business rules when altering the collection.