How does .Contains work inside of a .All()?
I'm looking at a piece of code that is:
return parts.All(format.Contains);
parts
is a ReadOnlyCollection<string> and format
is a string.
How is .Contains
in there without the ()? Isn't it a call itself?4 Replies
its just a short way to do
x => format.Contains(x)
its called "method group syntax"oh interesting. never heard of it before. thanks!
It's because
.All()
requires a Func<TSource, bool>
, so any method that takes a TSource
and returns a bool
.Contains()
happens to be a method that takes a TSource
and return bool
In slightly more detail...
parts.All(format.Contains)
is shorthand for parts.All(new Func<TSource, bool>(format.Contains))
. So you're taking the method format.Contains
, and creating a new delegate which points to it (new Func...
), then passing that delegate instance to parts.All
.
parts.All(x => format.Contains(x))
is shorthand for (something like):
So the x => format.Contains(x)
is shorthand for generating a whole new method, and because it captures something (format
) that method needs to be inside a whole new generated class. Then we create a new delegate instance as before, pointing to the generated method on the generated class, and pass that to parts.All
.
See exactly what's going on on shaplab: https://sharplab.io/#v2:EYLgtghglgdgPgAQAwAIEEYAsBuAsAKGTXQDoAZWARz3wIQGY0AmFAYRQG8CUe1HgA9gIA2KALIAKCgGcALgB5YsgHwoADhABOs6QBoUMhUtUAzAZsiyAlJ2697CAOzqtOkgEEYATwkAPFAC8puaWJKwCMLLQMNJ+VlY09gC+BCm0+EA
Also note that that pattern has high complexity -- for every element in parts
, you're having to search through every element in format
. This makes it O(n * m)
where n = parts.Count
and m = format.Count
.
It would be much more efficient to do something like parts.ToHashSet().IsSubsetOf(format)
or !parts.Except(format).Any()
. Those have complexity O(n + m)
.