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
Pobiega
Pobiega6mo ago
its just a short way to do x => format.Contains(x) its called "method group syntax"
Nacho Man Randy Cabbage
oh interesting. never heard of it before. thanks!
Angius
Angius6mo ago
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
canton7
canton76mo ago
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):
private class CompilerGeneratedClass
{
public Format format;
public bool CompilerGeneratedMethod(TSource x)
{
return format.Contains(x);
}
}

// ...

var c = new CompilerGeneratedClass();
c.format = format;
parts.All(new Func<TSource, bool>(c.CompilerGeneratedMethod));
private class CompilerGeneratedClass
{
public Format format;
public bool CompilerGeneratedMethod(TSource x)
{
return format.Contains(x);
}
}

// ...

var c = new CompilerGeneratedClass();
c.format = format;
parts.All(new Func<TSource, bool>(c.CompilerGeneratedMethod));
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).
Want results from more Discord servers?
Add your server