I prefer to use extension methods for the basic LINQ operations: Where()
, Select
, but for complex Select()
, SelectM开发者_开发问答any()
, and especially OrderBy().ThenBy()
statements I find the query syntax to be much more readable and natural.
Today I found myself with the following query:
from c in _myObject.ObjectsParent.ParentsEnumerable
.Where(c =>
c == anotherObject || c.Parent == anotherObject)
from q in c.MyObjectsEnumerable
orderby c.SortKey, q.Description
select new { Item = q, Text = c.Description + " -> " + q.Description };
Is it dangerous (for readability, maintainability, or any other reason) to mix query and extension syntax?
This has potential to be very subjective, if it is, I'm sorry if it doesn't meet the requirements for a good subjective question. Let me know if I can improve it!
Is it dangerous (for readability, maintainability, or any other reason) to mix query and extension syntax?
The biggest danger I'd see is the potential addition of "surprise" in your code, especially when viewed by other developers.
From a compilation standpoint, the query syntax is translated directly into the extension method calls, so there isn't necessarily a technical problem here. However, this is potentially going to be adding extra method calls that wouldn't, at a first glance, be expected by many developers. This could lead to a potential maintainability problem.
That being said, if done sparingly and with good reason, I don't feel that there is a real problem with mixing the syntax. This is actually quite common - for example, if you want to write in query syntax, but need to fully evaluate, it's often wrapped in parenthesis with .ToList() added - or if you want to use PLINQ with query syntax, it's often from x in collection.AsParallel()
, which is technically mixing syntax as well...
You could do something like this to make things a little easier.
var firstQuery = _myObject.ObjectsParent.ParentsEnumerable
.Where(c => c == anotherObject || c.Parent == anotherObject);
var secondQuery = from q in firstQuery.MyObjectsEnumerable
orderby firstQuery.SortKey, q.Description
select new { Item = q,
Text = firstQuery.Description + " -> " + q.Description };
Now your queries aren't mixed
This is kind of a judgment call, but many "best practice"-type questions tend to be, at least at first. My opinion is that you should use one or the other within a single statement. Not really for any "danger" inherent in mixing, but for clarity.
In this particular case, the where clause is very simple, and I would refactor it into query syntax.
There are however cases that cannot be elegantly expressed in query syntax. In cases where it is simply unavoidable to mix syntaxes, the queries would (again IMO) be more readable if you split out the method chain into its own variable, then simply referenced that variable in the query-syntaxed statement. Using yours as a model:
//The method chain can be pulled out as its own variable...
var filteredParents = _myObject.ObjectsParent.ParentsEnumerable
.Where(c => c == anotherObject || c.Parent == anotherObject);
//...which you can then substitute in a now purely query-syntax statement
from c in filteredParents
from q in c.MyObjectsEnumerable
orderby c.SortKey, q.Description
select new { Item = q, Text = c.Description + " -> " + q.Description };
I don't think it's dangerous to mix, it think it depends on what's more readable, query syntax is very readable, but not as flexable, so mixing some chaining seems like a small price to pay. I guess the answer is whether you think the following fully chained is more readable then what you wrote, I personally think yours is easier to read.
_myObject.ObjectsParent
.ParentsEnumerable
.Where(c => c == anotherObject || c.Parent == anotherObject)
.SelectMany(c => c.MyObjectsEnumerable, (c, q) => new {c, q})
.OrderBy(t => t.c.SortKey)
.ThenBy(t => t.q.Description)
.Select(t => new {Item = t.q, Text = t.c.Description + " -> " + t.q.Description});
I use the extension methods, my colleague uses the query syntax. There is no difference.
I would however say that you should break a large query into smaller ones for debugging and readability as there are typically no time costs.
Having done this myself (although not for .Where, but for .Cast) I'd say it very much depends what extension methods you're calling.
e.g. I felt perfectly entitled to use .Cast because it wasn't available in the syntactic sugar (AFAIK) but would probably avoid .Where, because that has a representation in the query syntax.
Having said that, I'd probably use .Select to mutate data in a query too... But I'm a bit of a sadist.
精彩评论