简体   繁体   中英

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.Except 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> , and System.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 throw NotSupportedException .

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[] implements IEnumerable<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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM