Extension Method In LINQ

Extension Methods

Extension methods are one important piece of the query architecture. Extension methods combine the flexibility of “duck typing” made popular in dynamic languages with the performance and compile-time validation of statically-typed languages. With extension methods third parties may augment the public contract of a type with new methods while still allowing individual type authors to provide their own specialized implementation of those methods.

Extension methods are defined in static classes as static methods, but are marked with the [System.Runtime.CompilerServices.Extension] attribute in CLR metadata. Languages are encouraged to provide a direct syntax for extension methods. In C#, extension methods are indicated by the this modifier which must be applied to the first parameter of the extension method. Let’s look at the definition of the simplest query operator, Where:

namespace System.Linq {

  using System;

  using System.Collections.Generic;

  public static class Enumerable {

    public static IEnumerable<T> Where<T>(

             this IEnumerable<T> source,

             Func<T, bool> predicate) {

      foreach (T item in source)

        if (predicate(item))

          yield return item;

    }

  }

}

The type of the first parameter of an extension method indicates what type the extension applies to. In the example above, the Where extension method extends the type IEnumerable<T>. Because Where is a static method, we can invoke it directly just like any other static method:

IEnumerable<string> query = Enumerable.Where(names,

                                          s => s.Length < 6);

However, what makes extension methods unique is that they can also be invoked using instance syntax:

IEnumerable<string> query = names.Where(s => s.Length < 6);

Extension methods are resolved at compile-time based on which extension methods are in scope. When a namespace is imported with a using statement in C# or an Import statement in Visual Basic, all extension methods that are defined by static classes from that namespace are brought into scope.

The standard query operators are defined as extension methods in the type System.Linq.Enumerable. When examining the standard query operators, you’ll notice that all but a few of them are defined in terms of the IEnumerable<T> interface. This means that every IEnumerable<T>-compatible information source gets the standard query operators simply by adding the following using statement in C#:

using System.Linq; // makes query operators visible

Users who want to replace the standard query operators for a specific type may either: define their own same-named methods on the specific type with compatible signatures, or define new same-named extension methods that extend the specific type. Users who want to eschew the standard query operators altogether can simply not put System.Linq into scope and write their own extension methods for IEnumerable<T>.

Extension methods are given the lowest priority in terms of resolution and are only used if there is no suitable match on the target type and its base types. This allows user-defined types to provide their own query operators that take precedence over the standard operators. For example, consider the following custom collection:

public class MySequence : IEnumerable<int> {

  public IEnumerator<int> GetEnumerator() {

    for (int i = 1; i <= 10; i++)

      yield return i;

  }

  IEnumerator IEnumerable.GetEnumerator() {

    return GetEnumerator();

  }

  public IEnumerable<int> Where(Func<int, bool> filter) {

    for (int i = 1; i <= 10; i++)

      if (filter(i))

        yield return i;

  }

}

Given this class definition, the following program will use the MySequence.Where implementation, not the extension method, as instance methods take precedence over extension methods:

MySequence s = new MySequence();

foreach (int item in s.Where(n => n > 3))

    Console.WriteLine(item);

The OfType operator is one of the few standard query operators that doesn’t extend an IEnumerable<T>-based information source. Let’s look at the OfType query operator:

public static IEnumerable<T> OfType<T>(this IEnumerable source) {

  foreach (object item in source)

    if (item is T)

      yield return (T)item;

}

OfType accepts not only IEnumerable<T>-based sources, but also sources that are written against the non-parameterized IEnumerable interface that was present in version 1.0 of the .NET Framework. The OfType operator allows users to apply the standard query operators to classic .NET collections like this:

// “classic” cannot be used directly with query operators

IEnumerable classic = new OlderCollectionType();

// “modern” can be used directly with query operators

IEnumerable<object> modern = classic.OfType<object>();

In this example, the variable modern yields the same sequence of values as does classic. However, its type is compatible with modern IEnumerable<T> code, including the standard query operators.

The OfType operator is also useful for newer information sources, as it allows filtering values from a source based on type. When producing the new sequence, OfType simply omits members of the original sequence that are not compatible with the type argument. Consider this simple program that extracts strings from a heterogeneous array:

object[] vals = { 1, “Hello”, true, “World”, 9.1 };

IEnumerable<string> justStrings = vals.OfType<string>();

When we enumerate the justStrings variable in a foreach statement, we’ll get a sequence of two strings: “Hello” and “World.”

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s