2012-07-05 13 views
13

Quando provo ad aggiungere un metodo di estensione utilizzando .NET 2.0 o 3.0 di runtime, ottengo l'errore:Posso utilizzare i metodi di estensione e LINQ in .NET 2.0 o 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?

Ma non riesco a trovare System.Core nell'elenco dei riferimenti disponibili quando si tenta di aggiungilo al progetto. Cosa devo fare per poter utilizzare i metodi di estensione e a turno LINQ nei miei progetti?

risposta

28

I metodi di estensione non sono stati aggiunti a .NET fino alla versione 3.5. Tuttavia, non è stata una modifica al CLR, ma a change to the compiler che li ha aggiunti, quindi puoi ancora usarli nei tuoi progetti 2.0 e 3.0! L'unico requisito è che devi avere un compilatore in grado di creare 3.5 progetti per poter eseguire questa soluzione alternativa (Visual   Studio   2008 e successivo).

L'errore che si ottiene quando si tenta di utilizzare un metodo di estensione è fuorviante in quanto non è veramente necessario System.Core.dll per utilizzare i metodi di estensione. Quando si utilizza un metodo di estensione, dietro le quinte, il compilatore sta aggiungendo l'attributo [Extension] alla funzione. Se hai un compilatore che capisce cosa fare con l'attributo [Extension] puoi usarlo nei tuoi progetti 2.0 e 3.0 se crei tu stesso l'attributo.

Basta aggiungere la seguente classe al progetto e si può quindi iniziare a utilizzare metodi di estensione:

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

Il blocco di codice di cui sopra è seduto all'interno System.Core.Dll, così che è il motivo per cui l'errore dice è necessario includere la DLL file per usarli.


Ora se si desidera la funzionalità LINQ che richiederà un po 'di lavoro in più. Dovrai implementare nuovamente i metodi di estensione da solo. Per simulare la piena funzionalità di LINQ to SQL il codice può diventare piuttosto complicato. Tuttavia, se si utilizza semplicemente LINQ to Objects, la maggior parte dei metodi LINQ non è complicata da implementare. Ecco alcuni LINQ   a   Funzioni di sostituzione di oggetti da un progetto che ho scritto per iniziare.

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

Una biblioteca con il pieno ri-implemenation di LINQ   per   oggetti con l'ExtensionAttribute già aggiunto può essere trovato nel LinqBridge progetto (Grazie Allon Guralnek).

+0

È importante sottolineare che i metodi di LinqReplacement funzionano solo con Linq to Objects. Non funzionerà per Linq su Sql. Sembra che molte persone non capiscano che c'è una differenza. Ma ancora +1 – cadrell0

+0

Non è necessario implementare nuovamente i metodi di estensione da soli. Il provider completo LINQ-to-Objects è già stato implementato per .NET 2.0 molto tempo fa come [LinqBridge] (http://linqbridge.googlecode.com/). E include già "ExtensionAttribute" che consente di creare metodi di estensione in .NET 2.0 con VS 2008 e versioni successive. –

+0

@AllonGuralnek Grazie per il collegamento, aggiornato la risposta e ti ha dato credito. –

Problemi correlati