Why can Enumerable.Except be used on a string array in C#?
Example
Here is a code example I found at the Pete on Software blog:
var listThree = new string[] { "Pete", "On", "Software" };
var listFour = new string[] { "Joel", "On", "Software" };
stringExcept = listThree.Except(listFour);
The code compiles and runs. So far so good.
Question
However, I don't understand why it works.
So, can anyone explain why I can use Enumerable.Except
on a string array?
Perhaps, it will be clear to me if someone could explain how to read the signature of Enumerable.Exc开发者_高级运维ept
and give me a code example:
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second
)
What I know
I know the concepts of generics and extension methods. But obviously not good enough to understand the code example above. I have also already used some basic Linq queries.
Except
is an extension method which extends any type that implements IEnumerable<T>
. This includes the System.Array type which implements IEnumerable<T>
.
The note on the linked page explains why the docs don't show System.Array
implementing IEnumerable<T>
In the .NET Framework version 2.0, the Array class implements the
System.Collections.Generic.IList<T>
,System.Collections.Generic.ICollection<T>
, andSystem.Collections.Generic.IEnumerable<T>
generic interfaces. The implementations are provided to arrays at run time, and therefore are not visible to the documentation build tools. As a result, the generic interfaces do not appear in the declaration syntax for the Array class, and there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations). The key thing to be aware of when you cast an array to one of these interfaces is that members which add, insert, or remove elements throwNotSupportedException
.
It just says that if you have an IEnumerable
of a given type TSource
in this case string
you can Except it with another IEnumerable
of the same type and get a third IEnumerable
of the same type back. The key point is that the two IEnumerable
inputs have to be the same (and obviously the return will be of the same type).
An array of T (or say a T[]
), is also an IEnumerable<T>
. In your question, T is System.String
. And Enumerable.Except
is an extension method on IEnumerable<T>
, so it's also working for a string[]
. And stringExcept = listThree.Except(listFour);
equals to
stringExcept = Enumerable.Except(listThree, listFour).
The compiler will match the TSource
argument to string as a string array implements the IEnumerable<string>
interface and thus matches the first argument of the extension method. So the answer is two things:
string[]
implementsIEnumerable<string>
- The compiler is intelligent enough to infer the generic arguments
The Except method returns the elements in the first enumerable that do not also appear in the
second enumerable. So in the case you specified, the result would be {"Pete", "Joel"}
.
In this case, thinking in terms of string arrays is perhaps a red herring. It might be more advantageous to think in terms of object equality (http://msdn.microsoft.com/en-us/library/system.object.equals.aspx).
The Microsoft documentation is here: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.except.aspx
精彩评论