2012-07-05 6 views
13

Wenn ich versuche, eine Erweiterungsmethode mit .NET 2.0 oder 3.0 Laufzeit hinzuzufügen, ich den Fehler:Kann ich Erweiterungsmethoden und LINQ in .NET 2.0 oder 3.0 verwenden?

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?

Aber ich kann nicht System.Core in der Liste der verfügbaren Referenzen finden, wenn ich versuche, Fügen Sie es dem Projekt hinzu. Was muss ich tun, um Erweiterungsmethoden verwenden zu können und umgekehrt in meinen Projekten LINQ?

Antwort

28

Erweiterungsmethoden wurden bis 3.5 nicht zu .NET hinzugefügt. Es war jedoch keine Änderung an der CLR, sondern a change to the compiler, die sie hinzugefügt hat, so dass Sie sie immer noch in Ihren 2.0 und 3.0 Projekten verwenden können! Die einzige Voraussetzung ist, dass Sie einen Compiler haben müssen, der 3.5 Projekte erstellen kann, um diese Problemumgehung zu ermöglichen (Visual   Studio   2008 und höher).

Der Fehler, den Sie erhalten, wenn Sie eine Erweiterungsmethode, wie Sie System.Core.dll nicht wirklich irreführend zu verwenden versuchen müssen Erweiterungsmethoden verwenden. Wenn Sie im Hintergrund eine Erweiterungsmethode verwenden, fügt der Compiler der Funktion das Attribut [Extension] hinzu. Wenn Sie einen Compiler haben, der versteht, was mit dem Attribut [Extension] zu tun ist, können Sie es in Ihren 2.0- und 3.0-Projekten verwenden, wenn Sie das Attribut selbst erstellen.

Fügen Sie einfach die folgende Klasse zu einem Projekt und Sie können dann Erweiterungsmethoden beginnen mit:

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

Der obige Codeblock innerhalb System.Core.Dll sitzt, so dass ist, warum der Fehler sagt müssen Sie die DLL enthalten Datei, um sie zu verwenden.


Jetzt, wenn Sie LINQ-Funktionalität möchten, die ein wenig mehr Arbeit benötigen. Sie müssen die Erweiterungsmethoden selbst erneut implementieren. Um die volle LINQ to SQL Funktionalität nachzuahmen, kann der Code ziemlich kompliziert werden. Wenn Sie jedoch nur LINQ to Objects verwenden, sind die meisten LINQ-Methoden nicht kompliziert zu implementieren. Hier sind ein paar LINQ   zu   Objects Ersatzfunktionen aus einem Projekt, das ich ausschrieb, um loszulegen.

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; 
    } 
} 

Eine Bibliothek mit der vollen Wieder Implemenation von LINQ  -  Objekten mit den ExtensionAttribute bereits hinzugefügt kann im LinqBridge Projekt gefunden werden (Danke Allon Guralnek).

+0

Es ist wichtig darauf hinzuweisen, dass Ihre LinqReplacement-Methoden nur für Linq to Objects funktionieren. Es wird nicht funktionieren für Linq zu Sql. Es scheint, als würden viele Leute nicht erkennen, dass es einen Unterschied gibt. Aber immer noch +1 – cadrell0

+0

Sie müssen die Erweiterung Methoden nicht erneut implementieren. Der vollständige LINQ-to-Objects-Provider wurde bereits vor langer Zeit als [LinqBridge] (http://linqbridge.googlecode.com/) für .NET 2.0 neu implementiert. Und es enthält bereits das ExtensionAttribute, mit dem Sie Erweiterungsmethoden in .NET 2.0 mit VS 2008 und höher erstellen können. –

+0

@AllonGuralnek Danke für den Link, aktualisiert die Antwort und gab Ihnen Kredit. –