2012-07-05 20 views
13

Gdy próbuję dodać metodę rozszerzenia przy użyciu .NET 2.0 lub 3.0 Runtime, pojawia się błąd:Czy mogę używać metod rozszerzających i LINQ w .NET 2.0 lub 3.0?

Cannot define a new extension method because the compiler required type 'System.Runtime.CompilerServices.ExtensionAttribute' cannot be found. Are you missing a reference to System.Core.dll?

Ale nie mogę znaleźć System.Core w liście dostępnych referencji przy próbie dodaj go do projektu. Co muszę zrobić, aby móc korzystać z metod rozszerzeń, aw przypadku moich projektów - z kolei LINQ?

Odpowiedz

28

Metody rozszerzeń nie zostały dodane do .NET do wersji 3.5. Jednak nie była to zmiana w CLR, ale dodała je, więc nadal można z nich korzystać w projektach 2.0 i 3.0! Jedynym wymaganiem jest posiadanie kompilatora, który może utworzyć 3.5 projekty, aby móc wykonać to obejście (Visual   Studio   2008 i wyżej).

Błąd, który pojawia się przy próbie użycia metody rozszerzenia, jest mylący, ponieważ nie potrzebujesz naprawdę System.Core.dll, aby użyć metod rozszerzenia. Gdy używasz metody rozszerzenia za kulisami, kompilator dodaje do tej funkcji atrybut [Extension]. Jeśli masz kompilator, który rozumie, co zrobić z atrybutem [Extension], możesz go użyć w projektach 2.0 i 3.0, jeśli sam utworzysz atrybut.

Wystarczy dodać następujące klasy do projektu, a następnie można zacząć używać metod rozszerzeń:

namespace System.Runtime.CompilerServices 
{ 
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 
    public class ExtensionAttribute : Attribute 
    { 
    } 
} 

Powyższy blok kodu siedzi wewnątrz System.Core.Dll, więc dlatego błąd mówi, że trzeba dołączyć DLL plik do ich użycia.


Teraz, jeśli chcesz funkcjonalność LINQ, która wymaga trochę dodatkowej pracy. Będziesz musiał ponownie wprowadzić metody rozszerzenia samodzielnie. Aby naśladować pełną funkcjonalność LINQ to SQL, kod może stać się dość skomplikowany. Jednakże, jeśli używasz tylko LINQ to Objects większość metod LINQ nie jest skomplikowana w implementacji. Oto kilka funkcji LINQ   do   Funkcje zastępowania obiektów z projektu, który napisałem, aby zacząć.

public static class LinqReplacement 
{ 
    public delegate TResult Func<T, TResult>(T arg); 
    public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2); 

    public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (predicate == null) 
      throw new ArgumentNullException("predicate"); 

     foreach (TSource item in source) 
     { 
      if (predicate(item) == true) 
       return item; 
     } 

     throw new InvalidOperationException("No item satisfied the predicate or the source collection was empty."); 
    } 

    public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     foreach (TSource item in source) 
     { 
      return item; 
     } 

     return default(TSource); 
    } 

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) 
    { 
     foreach (object item in source) 
     { 
      yield return (TResult)item; 
     } 
    } 

    public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (selector == null) 
      throw new ArgumentNullException("selector"); 

     foreach (TSource item in source) 
     { 
      foreach (TResult subItem in selector(item)) 
      { 
       yield return subItem; 
      } 
     } 
    } 

    public static int Count<TSource>(this IEnumerable<TSource> source) 
    { 
     var asCollection = source as ICollection; 
     if(asCollection != null) 
     { 
      return asCollection.Count; 
     } 

     int count = 0; 
     foreach (TSource item in source) 
     { 
      checked //If we are counting a larger than int.MaxValue enumerable this will cause a OverflowException to happen when the counter wraps around. 
      { 
       count++; 
      } 
     } 
     return count; 
    } 
} 

biblioteki z pełnego ponownego implementacja LINQ   do   obiektów z ExtensionAttribute już dodanej można znaleźć w projekcie (Dzięki Allon Guralnek) LinqBridge.

+0

Ważne jest, aby zwrócić uwagę, że metody LinqReplacement będą działać tylko dla Linq to Objects. To nie zadziała dla Linq do Sql. Wygląda na to, że wielu ludzi nie zdaje sobie sprawy, że istnieje różnica. Ale wciąż +1 – cadrell0

+0

Nie musisz ponownie wdrażać metod rozszerzenia. Kompletny dostawca LINQ-to-Objects został już ponownie wdrożony dla .NET 2.0 dawno temu jako [LinqBridge] (http://linqbridge.googlecode.com/). I zawiera już 'ExtensionAttribute', który pozwala na tworzenie metod rozszerzeń w .NET 2.0 z VS 2008 i wyżej. –

+0

@AllonGuralnek Dzięki za link, zaktualizowałeś odpowiedź i przyznałeś kredyt. –