LINQ is such a powerful feature that developers are likely to use it everywhere in code, just like foreach blocks and if statement are. LINQ comes with different flavors of APIs, such as LINQ for Objects, LINQ for SQL, LINQ for XML, etc., each one of them being really powerful on what it does. Even though there are no restrictions as to where LINQ could be used, some of its APIs should be constricted to only be used in certain layers of code.
For example, LINQ for SQL should only be used by the Data Access Layer (DAL). The classes created to map objects to tables on the database (usually referred to as data context) should never be touched by any layer other than the DAL. Running a query from the UI against data contexts is like going directly to the database, which has never been a good idea.
LINQ for Objects, on the other hand, can (and should) be used everywhere. For instance, let’s say a given form has some logic that whenever a given condition is met, all the buttons on the form should be disabled. The traditional code for that would be a mix of foreach, typeof (or is), and if:
foreach (Control control in this.Controls)
{
if (control is Button)
{
control.Enabled = false;
}
}
The version with LINQ for Objects would look like so:
var buttons =
from control in this.Controls.Cast<Control>().OfType<Button>()
select control;
foreach (var button in buttons)
{
button.Enabled = false;
}
The difference here isn’t that big because the only condition we’re looking for is to get every control of type Button within the form. The differences are more apparent in more complex scenarios.
Another example would be a case where we have a collection of entities representing customers, and we want to query that collection, and the outcome should be a collection of edit-forms editing the entities returned by the query. Like this:
var customers = new List<CustomerBusinessEntity>{
new CustomerBusinessEntity("Claudio Lassala"),
new CustomerBusinessEntity("John Jones"),
new CustomerBusinessEntity("Cartman Smith")};
var customerForms =
from customer in customers
where customer.Name.StartsWith(this.txtName.Text)
select new CustomerEditForm(customer);
foreach (var form in customerForms)
{
form.Show();
}
The sky is the limit.
As I get a chance, I’ll probably be writing some custom FxCop rule to make sure I catch developers trying to run queries from the UI against data context (sort of like the one we currently have where we don’t allow developer to create IDbConnection objects directly, since all data access goes through our business objects).
What was the Spiderman line: “With great power comes great responsibility”? J